loadtest 7.1.0 → 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.
@@ -0,0 +1,13 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: alexfernandez
4
+ patreon: # Replace with a single Patreon username
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ otechie: # Replace with a single Otechie username
12
+ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13
+ custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
package/README.md CHANGED
@@ -77,7 +77,7 @@ but the resulting figure is much more robust.
77
77
  Using the provided API it is very easy to integrate loadtest with your package, and run programmatic load tests.
78
78
  loadtest makes it very easy to run load tests as part of systems tests, before deploying a new version of your software.
79
79
  The result includes mean response times and percentiles,
80
- so that you can abort deployment e.g. if 99% of the requests don't finish in 10 ms or less.
80
+ so that you can abort deployment e.g. if 99% of all requests don't finish in 10 ms or less.
81
81
 
82
82
  ### Usage Don'ts
83
83
 
@@ -85,14 +85,18 @@ so that you can abort deployment e.g. if 99% of the requests don't finish in 10
85
85
  but it is still limited.
86
86
  `loadtest` saturates a single CPU pretty quickly,
87
87
  so it uses half the available cores in your processor.
88
- If you see that the Node.js processes are above 100% usage in `top`,
89
- which happens approx. when your load is above 4000~5000 rps per core,
90
- please adjust the number of cores.
88
+ The Node.js processes can reach 100% usage in `top`,
89
+ which happens approx. when your load is above 4000~7000 rps per core.
90
+ In this case please adjust the number of cores.
91
91
  So for instance with eight cores you can expect to get a maximum performance of
92
- 8 * 5000 ~ 40 krps.
93
- (You can measure the practical limits of `loadtest` on your specific test machines by running it against a simple
92
+ 8 * 5000 = 40 krps.
93
+
94
+ You can measure the practical limits of `loadtest` on your specific test machines by running it against a simple
94
95
  [test server](#test-server)
95
- and seeing when it reaches 100% CPU.)
96
+ and seeing when it reaches 100% CPU. Run the following commands on two different consoles:
97
+
98
+ $ node bin/testserver.js
99
+ $ node bin/loadtest.js -n 1000000 -c 100 http://localhost:7357/
96
100
 
97
101
  If you have reached the limits of `loadtest` even after using all cores,
98
102
  there are other tools that you can try.
@@ -100,7 +104,7 @@ there are other tools that you can try.
100
104
  * [AutoCannon](https://www.npmjs.com/package/autocannon): also an `npm` package,
101
105
  awesome tool with an interface similar to `wrk`.
102
106
  * [Apache `ab`](http://httpd.apache.org/docs/2.2/programs/ab.html)
103
- has great performance, but it is also limited by a single CPU performance.
107
+ has great performance, but it is limited by a single CPU performance.
104
108
  Its practical limit is somewhere around ~40 krps.
105
109
  * [weighttp](http://redmine.lighttpd.net/projects/weighttp/wiki) is also `ab`-compatible
106
110
  and is supposed to be very fast (the author has not personally used it).
@@ -112,43 +116,57 @@ It may need installing from source though, and its interface is not `ab`-compati
112
116
 
113
117
  The following parameters are compatible with Apache ab.
114
118
 
115
- #### `-n requests`
119
+ #### `-t`, `--maxSeconds`
120
+
121
+ Max number of seconds to wait until requests no longer go out.
122
+ Default is 10 seconds, applies only if no `--maxRequests` is specified.
123
+
124
+ Note: this is different than Apache `ab`, which stops _receiving_ requests after the given seconds.
125
+
126
+ **Warning**: max seconds used to have no default value,
127
+ so tests would run indefinitely if no `--maxSeconds` and no `--maxRequests` were specified.
128
+ Max seconds was changed to default to 10 in version 8.
129
+
130
+ #### `-n`, `--maxRequests`
116
131
 
117
132
  Number of requests to send out.
118
- Default is no limit; will keep on sending if not specified.
133
+ Default is no limit;
134
+ will keep on sending until the time limit in `--maxSeconds` is reached.
119
135
 
120
136
  Note: the total number of requests sent can be bigger than the parameter if there is a concurrency parameter;
121
137
  loadtest will report just the first `n`.
122
138
 
123
- #### `-c concurrency`
139
+ #### `-c`, `--concurrency`
124
140
 
125
141
  loadtest will create a certain number of clients; this parameter controls how many.
126
142
  Requests from them will arrive concurrently to the server.
127
- Default value is 1.
143
+ Default value is 10.
128
144
 
129
145
  Note: requests are not sent in parallel (from different processes),
130
146
  but concurrently (a second request may be sent before the first has been answered).
147
+ Does not apply if `--requestsPerSecond` is specified.
131
148
 
132
- #### `-t timelimit`
133
-
134
- Max number of seconds to wait until requests no longer go out.
135
- Default is no limit; will keep on sending if not specified.
149
+ Beware: if concurrency is too low then it is possible that there will not be enough clients
150
+ to send all the supported traffic,
151
+ adjust it with `-c` if needed.
136
152
 
137
- Note: this is different than Apache `ab`, which stops _receiving_ requests after the given seconds.
153
+ **Warning**: concurrency used to have a default value of 1,
154
+ until it was changed to 10 in version 8.
138
155
 
139
- #### `-k` or `--keepalive`
156
+ #### `-k`, `--keepalive`
140
157
 
141
- Open connections using keep-alive: use header 'Connection: Keep-alive' instead of 'Connection: Close'.
158
+ Open connections using keep-alive:
159
+ use header `Connection: keep-alive` instead of `Connection: close`.
142
160
 
143
161
  Note: Uses [agentkeepalive](https://npmjs.org/package/agentkeepalive),
144
162
  which performs better than the default node.js agent.
145
163
 
146
- #### `-C cookie-name=value`
164
+ #### `-C`, `--cookie cookie-name=value`
147
165
 
148
166
  Send a cookie with the request. The cookie `name=value` is then sent to the server.
149
167
  This parameter can be repeated as many times as needed.
150
168
 
151
- #### `-H header:value`
169
+ #### `-H`, `--header header:value`
152
170
 
153
171
  Send a custom header with the request. The line `header:value` is then sent to the server.
154
172
  This parameter can be repeated as many times as needed.
@@ -168,19 +186,19 @@ Note: if you need to add a header with spaces, be sure to surround both header a
168
186
 
169
187
  $ loadtest -H "Authorization: Basic xxx=="
170
188
 
171
- #### `-T content-type`
189
+ #### `-T`, `--contentType`
172
190
 
173
191
  Set the MIME content type for POST data. Default: `text/plain`.
174
192
 
175
- #### `-P POST-body`
193
+ #### `-P`, `--postBody`
176
194
 
177
195
  Send the string as the POST body. E.g.: `-P '{"key": "a9acf03f"}'`
178
196
 
179
- #### `-A PATCH-body`
197
+ #### `-A`, `--patchBody`
180
198
 
181
199
  Send the string as the PATCH body. E.g.: `-A '{"key": "a9acf03f"}'`
182
200
 
183
- #### `-m method`
201
+ #### `-m`, `--method`
184
202
 
185
203
  Set method that will be sent to the test URL.
186
204
  Accepts: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`,
@@ -194,7 +212,7 @@ Requires setting the method with `-m` and the type with `-T`.
194
212
  Example: `--data '{"username": "test", "password": "test"}' -T 'application/x-www-form-urlencoded' -m POST`
195
213
 
196
214
 
197
- #### `-p POST-file`
215
+ #### `-p`, `--postFile`
198
216
 
199
217
  Send the data contained in the given file in the POST body.
200
218
  Remember to set `-T` to the correct content-type.
@@ -218,7 +236,7 @@ export default function request(requestId) {
218
236
 
219
237
  See sample file in `sample/post-file.js`, and test in `test/body-generator.js`.
220
238
 
221
- #### `-u PUT-file`
239
+ #### `-u`, `--putFile`
222
240
 
223
241
  Send the data contained in the given file as a PUT request.
224
242
  Remember to set `-T` to the correct content-type.
@@ -229,7 +247,7 @@ to provide the body of each request.
229
247
  This is useful if you want to generate request bodies dynamically and vary them for each request.
230
248
  For examples see above for `-p`.
231
249
 
232
- #### `-a PATCH-file`
250
+ #### `-a`, `--patchFile`
233
251
 
234
252
  Send the data contained in the given file as a PATCH request.
235
253
  Remember to set `-T` to the correct content-type.
@@ -240,12 +258,12 @@ to provide the body of each request.
240
258
  This is useful if you want to generate request bodies dynamically and vary them for each request.
241
259
  For examples see above for `-p`.
242
260
 
243
- ##### `-r recover`
261
+ ##### `-r`, `--recover`
244
262
 
245
263
  Recover from errors. Always active: loadtest does not stop on errors.
246
264
  After the tests are finished, if there were errors a report with all error codes will be shown.
247
265
 
248
- #### `-s secureProtocol`
266
+ #### `-s`, `--secureProtocol`
249
267
 
250
268
  The TLS/SSL method to use. (e.g. TLSv1_method)
251
269
 
@@ -253,7 +271,7 @@ Example:
253
271
 
254
272
  $ loadtest -n 1000 -s TLSv1_method https://www.example.com
255
273
 
256
- #### `-V version`
274
+ #### `-V`, `--version`
257
275
 
258
276
  Show version number and exit.
259
277
 
@@ -261,25 +279,17 @@ Show version number and exit.
261
279
 
262
280
  The following parameters are _not_ compatible with Apache ab.
263
281
 
264
- #### `--rps requestsPerSecond`
282
+ #### `--rps`, `--requestsPerSecond`
265
283
 
266
284
  Controls the number of requests per second that are sent.
267
285
  Cannot be fractional, e.g. `--rps 0.5`.
268
286
  In this mode each request is not sent as soon as the previous one is responded,
269
287
  but periodically even if previous requests have not been responded yet.
270
288
 
271
- Note: Concurrency doesn't affect the final number of requests per second,
272
- since rps will be shared by all the clients. E.g.:
273
-
274
- loadtest <url> -c 10 --rps 10
275
-
276
- will send a total of 10 rps to the given URL, from 10 different clients
277
- (each client will send 1 request per second).
278
-
279
- Beware: if concurrency is too low then it is possible that there will not be enough clients
280
- to send all of the rps, adjust it with `-c` if needed.
289
+ Note: the `--concurrency` option will be ignored if `--requestsPerSecond` is specified;
290
+ clients will be created on demand.
281
291
 
282
- Note: --rps is not supported for websockets.
292
+ Note: `--rps` is not supported for websockets.
283
293
 
284
294
  #### `--cores number`
285
295
 
@@ -306,7 +316,7 @@ Setting this to 0 disables timeout (default).
306
316
  #### `-R requestGeneratorModule.js`
307
317
 
308
318
  Use a custom request generator function from an external file.
309
- See an example of a request generator module in [`--requestGenerator`](#requestGenerator) below.
319
+ See an example of a request generator module in [`requestGenerator`](doc/api.md#requestGenerator).
310
320
  Also see [`sample/request-generator.js`](sample/request-generator.js) for some sample code including a body
311
321
  (or [`sample/request-generator.ts`](sample/request-generator.ts) for ES6/TypeScript).
312
322
 
@@ -338,6 +348,16 @@ Sets the certificate for the http client to use. Must be used with `--key`.
338
348
 
339
349
  Sets the key for the http client to use. Must be used with `--cert`.
340
350
 
351
+ #### `--tcp` (experimental)
352
+
353
+ Option to use low level TCP sockets,
354
+ faster than the standard HTTP library.
355
+ Not all options are supported.
356
+
357
+ **Warning**: experimental option.
358
+ May not work with your test case.
359
+ See [TCP Sockets Performance](doc/tcp-sockets.md) for details.
360
+
341
361
  ### Test Server
342
362
 
343
363
  loadtest bundles a test server. To run it:
@@ -403,7 +423,7 @@ with concurrency 10 (only relevant results are shown):
403
423
  Requests per second: 368
404
424
  Total time: 44.503181166000005 s
405
425
 
406
- Percentage of the requests served within a certain time
426
+ Percentage of requests served within a certain time
407
427
  50% 4 ms
408
428
  90% 5 ms
409
429
  95% 6 ms
@@ -420,7 +440,7 @@ Now we will try a fixed rate of 1000 rps:
420
440
  Requests: 9546, requests per second: 1000, mean latency: 0 ms
421
441
  Requests: 14549, requests per second: 1000, mean latency: 20 ms
422
442
  ...
423
- Percentage of the requests served within a certain time
443
+ Percentage of requests served within a certain time
424
444
  50% 1 ms
425
445
  90% 2 ms
426
446
  95% 8 ms
@@ -451,7 +471,7 @@ Let us lower the rate to 500 rps:
451
471
  Requests per second: 488
452
472
  Total time: 20.002735398000002 s
453
473
 
454
- Percentage of the requests served within a certain time
474
+ Percentage of requests served within a certain time
455
475
  50% 1 ms
456
476
  90% 1 ms
457
477
  95% 1 ms
@@ -474,7 +494,7 @@ The result (with the same test server) is impressive:
474
494
  ...
475
495
  Requests per second: 4099
476
496
 
477
- Percentage of the requests served within a certain time
497
+ Percentage of requests served within a certain time
478
498
  50% 2 ms
479
499
  90% 3 ms
480
500
  95% 3 ms
@@ -487,7 +507,7 @@ Now we're talking! The steady rate also goes up to 2 krps:
487
507
  ...
488
508
  Requests per second: 1950
489
509
 
490
- Percentage of the requests served within a certain time
510
+ Percentage of requests served within a certain time
491
511
  50% 1 ms
492
512
  90% 2 ms
493
513
  95% 2 ms
@@ -567,6 +587,8 @@ see [doc/api.md](doc/api.md) for details.
567
587
  * `percent`: return error only for the given % of requests.
568
588
  * `logger(request, response)`: function to call after every request.
569
589
 
590
+ Returns a test server that you can `close()` when finished.
591
+
570
592
  ### Configuration file
571
593
 
572
594
  It is possible to put configuration options in a file named `.loadtestrc` in your working directory or in a file whose name is specified in the `loadtest` entry of your `package.json`. The options in the file will be used only if they are not specified in the command line.
package/bin/loadtest.js CHANGED
@@ -9,9 +9,9 @@ import {getHalfCores} from '../lib/cluster.js'
9
9
 
10
10
 
11
11
  const options = stdio.getopt({
12
+ maxSeconds: {key: 't', args: 1, description: 'Max time in seconds to wait for responses, default 10'},
12
13
  maxRequests: {key: 'n', args: 1, description: 'Number of requests to perform'},
13
- concurrency: {key: 'c', args: 1, description: 'Number of requests to make'},
14
- maxSeconds: {key: 't', args: 1, description: 'Max time in seconds to wait for responses'},
14
+ concurrency: {key: 'c', args: 1, description: 'Number of concurrent requests, default 10'},
15
15
  timeout: {key: 'd', args: 1, description: 'Timeout for each request in milliseconds'},
16
16
  contentType: {key: 'T', args: 1, description: 'MIME type for the body'},
17
17
  cookies: {key: 'C', multiple: true, description: 'Send a cookie as name=value'},
@@ -36,6 +36,7 @@ const options = stdio.getopt({
36
36
  cert: {args: 1, description: 'The client certificate to use'},
37
37
  quiet: {description: 'Do not log any messages'},
38
38
  cores: {args: 1, description: 'Number of cores to use', default: getHalfCores()},
39
+ tcp: {description: 'Use TCP sockets (experimental)'},
39
40
  agent: {description: 'Use a keep-alive http agent (deprecated)'},
40
41
  debug: {description: 'Show debug messages (deprecated)'},
41
42
  });
@@ -0,0 +1,21 @@
1
+ import {loadTest, startServer} from '../index.js'
2
+
3
+ const port = 7359;
4
+ const serverOptions = {port}
5
+
6
+
7
+ async function runTcpPerformanceTest() {
8
+ const server = await startServer(serverOptions)
9
+ const options = {
10
+ url: `http://localhost:${port}`,
11
+ method: 'GET',
12
+ tcp: true,
13
+ };
14
+ const result = await loadTest(options)
15
+ await server.close()
16
+ console.log(`Requests received: ${server.totalRequests}`)
17
+ result.show()
18
+ }
19
+
20
+ await runTcpPerformanceTest()
21
+
package/bin/testserver.js CHANGED
@@ -5,49 +5,51 @@ import {startServer} from '../lib/testserver.js'
5
5
  import {loadConfig} from '../lib/config.js'
6
6
  import {getHalfCores, runTask} from '../lib/cluster.js'
7
7
 
8
+ const configuration = loadConfig()
8
9
  const options = readOptions()
9
10
  start(options)
10
11
 
11
12
 
12
13
  function readOptions() {
13
14
  const options = stdio.getopt({
15
+ port: {key: 'p', args: 1, description: 'Port for the server'},
14
16
  delay: {key: 'd', args: 1, description: 'Delay the response for the given milliseconds'},
15
17
  error: {key: 'e', args: 1, description: 'Return an HTTP error code'},
16
- percent: {key: 'p', args: 1, description: 'Return an error (default 500) only for some % of requests'},
17
- cores: {key: 'c', args: 1, description: 'Number of cores to use, default is half the total', default: getHalfCores()}
18
+ percent: {key: 'P', args: 1, description: 'Return an error (default 500) only for some % of requests'},
19
+ cores: {key: 'c', args: 1, description: 'Number of cores to use, default is half the total', default: getHalfCores()},
20
+ body: {key: 'b', args: 1, description: 'Body to return, default "OK"'},
21
+ file: {key: 'f', args: 1, description: 'File to read and return as body'},
18
22
  });
19
- const configuration = loadConfig()
20
23
  if (options.args && options.args.length == 1) {
21
- options.port = parseInt(options.args[0], 10);
22
- if (!options.port) {
23
- console.error('Invalid port');
24
- options.printHelp();
25
- process.exit(1);
26
- }
24
+ options.port = options.port || options.args[0]
27
25
  }
28
- if(options.delay) {
29
- if(isNaN(options.delay)) {
30
- console.error('Invalid delay');
31
- options.printHelp();
32
- process.exit(1);
33
- }
34
- options.delay = parseInt(options.delay, 10);
26
+ return {
27
+ port: readInt(options, 'port'),
28
+ delay: readInt(options, 'delay'),
29
+ error: readInt(options, 'error'),
30
+ percent: readInt(options, 'percent'),
31
+ cores: readInt(options, 'cores'),
32
+ body: readString(options, 'body'),
33
+ file: readString(options, 'file'),
35
34
  }
35
+ }
36
36
 
37
- if(!options.delay) {
38
- options.delay = configuration.delay
39
- }
40
- if(!options.error) {
41
- options.error = configuration.error
42
- }
43
- if(!options.percent) {
44
- options.percent = configuration.percent
37
+ function readString(options, key) {
38
+ return options[key] || configuration[key]
39
+ }
40
+
41
+ function readInt(options, key) {
42
+ if (options[key] && isNaN(options[key])) {
43
+ console.error(`Invalid ${key}`);
44
+ options.printHelp();
45
+ process.exit(1);
45
46
  }
46
- return options
47
+ const value = readString(options, key)
48
+ return parseInt(value) || undefined
47
49
  }
48
50
 
49
51
  function start(options) {
50
- runTask(options.cores, async () => await startServer(options))
52
+ runTask(options.cores, async () => {await startServer(options)})
51
53
  }
52
54
 
53
55
 
package/doc/api.md CHANGED
@@ -37,7 +37,7 @@ result.show()
37
37
  console.log('Tests run successfully')
38
38
  ```
39
39
 
40
- The call returns a `Result` object that contains all info about the load test, also described below.
40
+ The call returns a `Result` object that contains all info about the load test, also described [below](#result).
41
41
  Call `result.show()` to display the results in the standard format on the console.
42
42
 
43
43
  As a legacy from before promises existed,
@@ -61,46 +61,6 @@ loadTest(options, function(error, result) {
61
61
  })
62
62
  ```
63
63
 
64
-
65
- Beware: if there are no `maxRequests` and no `maxSeconds`, then tests will run forever
66
- and will not call the callback.
67
-
68
- ### Result
69
-
70
- The latency result returned at the end of the load test contains a full set of data, including:
71
- mean latency, number of errors and percentiles.
72
- A simplified example follows:
73
-
74
- ```javascript
75
- {
76
- url: 'http://localhost:80/',
77
- maxRequests: 1000,
78
- maxSeconds: 0,
79
- concurrency: 10,
80
- agent: 'none',
81
- requestsPerSecond: undefined,
82
- totalRequests: 1000,
83
- percentiles: {
84
- '50': 7,
85
- '90': 10,
86
- '95': 11,
87
- '99': 15
88
- },
89
- effectiveRps: 2824,
90
- elapsedSeconds: 0.354108,
91
- meanLatencyMs: 7.72,
92
- maxLatencyMs: 20,
93
- totalErrors: 3,
94
- errorCodes: {
95
- '0': 1,
96
- '500': 2
97
- },
98
- }
99
- ```
100
-
101
- The `result` object also has a `result.show()` function
102
- that displays the results on the console in the standard format.
103
-
104
64
  ### Options
105
65
 
106
66
  All options but `url` are, as their name implies, optional.
@@ -110,23 +70,34 @@ See also the [simplified list](../README.md#loadtest-parameters).
110
70
 
111
71
  The URL to invoke. Mandatory.
112
72
 
113
- #### `concurrency`
73
+ #### `maxSeconds`
114
74
 
115
- How many clients to start in parallel.
75
+ Max number of seconds to run the tests.
76
+ Default is 10 seconds, applies only if no `maxRequests` is specified.
77
+
78
+ Note: after the given number of seconds `loadtest` will stop sending requests,
79
+ but may continue receiving tests afterwards.
80
+
81
+ **Warning**: max seconds used to have no default value,
82
+ so tests would run indefinitely if no `maxSeconds` and no `maxRequests` were specified.
83
+ Max seconds was changed to default to 10 in version 8.
116
84
 
117
85
  #### `maxRequests`
118
86
 
119
87
  A max number of requests; after they are reached the test will end.
88
+ Default is no limit;
89
+ will keep on sending until the time limit in `maxSeconds` is reached.
120
90
 
121
91
  Note: the actual number of requests sent can be bigger if there is a concurrency level;
122
92
  loadtest will report just on the max number of requests.
123
93
 
124
- #### `maxSeconds`
94
+ #### `concurrency`
125
95
 
126
- Max number of seconds to run the tests.
96
+ How many clients to start in parallel, default is 10.
97
+ Does not apply if `requestsPerSecond` is specified.
127
98
 
128
- Note: after the given number of seconds `loadtest` will stop sending requests,
129
- but may continue receiving tests afterwards.
99
+ **Warning**: concurrency used to have a default value of 1,
100
+ until it was changed to 10 in version 8.
130
101
 
131
102
  #### `timeout`
132
103
 
@@ -134,7 +105,7 @@ Timeout for each generated request in milliseconds. Setting this to 0 disables t
134
105
 
135
106
  #### `cookies`
136
107
 
137
- An array of cookies to send. Each cookie should be a string of the form name=value.
108
+ An array of cookies to send. Each cookie should be a string of the form `name=value`.
138
109
 
139
110
  #### `headers`
140
111
 
@@ -146,9 +117,6 @@ like this:
146
117
  accept: "text/plain;text/html"
147
118
  }
148
119
 
149
- Note: when using the API, the "host" header is not inferred from the URL but needs to be sent
150
- explicitly.
151
-
152
120
  #### `method`
153
121
 
154
122
  The method to use: POST, PUT. Default: GET.
@@ -317,6 +285,86 @@ function contentInspector(result) {
317
285
  }
318
286
  },
319
287
  ```
288
+
289
+ #### `tcp`
290
+
291
+ If true, use low-level TCP sockets.
292
+ Faster option that can increase performance by up to 10x,
293
+ especially in local test setups.
294
+
295
+ **Warning**: Experimental option.
296
+ May not work for your test case.
297
+ Not compatible with options `indexParam`, `statusCallback`, `requestGenerator`.
298
+ See [TCP Sockets Performance](doc/tcp-sockets.md) for details.
299
+
300
+ ### Result
301
+
302
+ The latency result returned at the end of the load test contains a full set of data, including:
303
+ mean latency, number of errors and percentiles.
304
+ A simplified example follows:
305
+
306
+ ```javascript
307
+ {
308
+ url: 'http://localhost:80/',
309
+ maxRequests: 1000,
310
+ maxSeconds: 0,
311
+ concurrency: 10,
312
+ agent: 'none',
313
+ requestsPerSecond: undefined,
314
+ totalRequests: 1000,
315
+ percentiles: {
316
+ '50': 7,
317
+ '90': 10,
318
+ '95': 11,
319
+ '99': 15
320
+ },
321
+ effectiveRps: 2824,
322
+ elapsedSeconds: 0.354108,
323
+ meanLatencyMs: 7.72,
324
+ maxLatencyMs: 20,
325
+ totalErrors: 3,
326
+ clients: 10,
327
+ errorCodes: {
328
+ '0': 1,
329
+ '500': 2
330
+ },
331
+ }
332
+ ```
333
+
334
+ The `result` object also has a `result.show()` function
335
+ that displays the results on the console in the standard format.
336
+
337
+ Some of the attributes (`url`, `concurrency`) will be identical to the parameters passed.
338
+ The following attributes can also be returned.
339
+
340
+ #### `totalRequests`
341
+
342
+ How many requests were actually processed.
343
+
344
+ #### `totalRequests`
345
+
346
+ How many requests resulted in an error.
347
+
348
+ #### `effectiveRps`
349
+
350
+ How many requests per second were actually processed.
351
+
352
+ #### `elapsedSeconds`
353
+
354
+ How many seconds the test lasted.
355
+
356
+ #### `meanLatencyMs`
357
+
358
+ Average latency in milliseconds.
359
+
360
+ #### `errorCodes`
361
+
362
+ Object containing a map with all status codes received.
363
+
364
+ #### `clients`
365
+
366
+ Number of concurrent clients started.
367
+ Should equal the concurrency level unless the `rps` option is specified.
320
368
 
321
369
  ### Start Test Server
322
370
 
@@ -330,7 +378,7 @@ await server.close()
330
378
  ```
331
379
 
332
380
  This function returns when the server is up and running,
333
- with an HTTP server which can be `close()`d when it is no longer useful.
381
+ with a server object which can be `close()`d when it is no longer useful.
334
382
  As a legacy from before promises existed,
335
383
  if an optional callback is passed as second parameter then it will not behave as `async`:
336
384
 
@@ -338,6 +386,9 @@ if an optional callback is passed as second parameter then it will not behave as
338
386
  const server = startServer({port: 8000}, error => console.error(error))
339
387
  ```
340
388
 
389
+ **Warning**: up until version 7 this function returned an HTTP server;
390
+ this was changed to a test server object with an identical `close()` method.
391
+
341
392
  The following options are available.
342
393
 
343
394
  #### `port`