loadtest 5.0.4 → 5.2.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 +46 -2
- package/index.d.ts +7 -2
- package/lib/httpClient.js +5 -1
- package/lib/loadtest.js +74 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -603,6 +603,25 @@ will be:
|
|
|
603
603
|
* ...
|
|
604
604
|
* body will also be replaced `body:{ userid: id_value }` will be `body:{ userid: id_1 }`
|
|
605
605
|
|
|
606
|
+
#### `indexParamCallback`
|
|
607
|
+
|
|
608
|
+
A function that would be executed to replace the value identified through `indexParam` through a custom value generator.
|
|
609
|
+
|
|
610
|
+
E.g.: if URL is `http://test.com/value` and `indexParam=value` and
|
|
611
|
+
```javascript
|
|
612
|
+
indexParamCallback: function customCallBack() {
|
|
613
|
+
return Math.floor(Math.random() * 10); //returns a random integer from 0 to 9
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
then the URL could be:
|
|
617
|
+
|
|
618
|
+
* http://test.com/1 (Randomly generated integer 1)
|
|
619
|
+
* http://test.com/5 (Randomly generated integer 5)
|
|
620
|
+
* http://test.com/6 (Randomly generated integer 6)
|
|
621
|
+
* http://test.com/8 (Randomly generated integer 8)
|
|
622
|
+
* ...
|
|
623
|
+
* body will also be replaced `body:{ userid: id_value }` will be `body:{ userid: id_<value from callback> }`
|
|
624
|
+
|
|
606
625
|
#### `insecure`
|
|
607
626
|
|
|
608
627
|
Allow invalid and self-signed certificates over https.
|
|
@@ -632,7 +651,7 @@ loadtest.loadTest(options, function(error) {
|
|
|
632
651
|
|
|
633
652
|
#### `statusCallback`
|
|
634
653
|
|
|
635
|
-
|
|
654
|
+
If present, this function executes after every request operation completes. Provides immediate access to test results while the
|
|
636
655
|
test batch is still running. This can be used for more detailed custom logging or developing your own spreadsheet or
|
|
637
656
|
statistical analysis of results.
|
|
638
657
|
|
|
@@ -673,6 +692,31 @@ loadtest.loadTest(options, function(error) {
|
|
|
673
692
|
});
|
|
674
693
|
```
|
|
675
694
|
|
|
695
|
+
|
|
696
|
+
In some situations request data needs to be available in the statusCallBack.
|
|
697
|
+
This data can be assigned to `request.labels` in the requestGenerator:
|
|
698
|
+
```javascript
|
|
699
|
+
const options = {
|
|
700
|
+
// ...
|
|
701
|
+
requestGenerator: (params, options, client, callback) => {
|
|
702
|
+
// ...
|
|
703
|
+
const randomInputData = Math.random().toString().substr(2, 8);
|
|
704
|
+
const message = JSON.stringify({ randomInputData })
|
|
705
|
+
const request = client(options, callback);
|
|
706
|
+
request.labels = randomInputData;
|
|
707
|
+
request.write(message);
|
|
708
|
+
return request;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
Then in statusCallBack the labels can be accessed through `result.labels`:
|
|
714
|
+
```javascript
|
|
715
|
+
function statusCallback(error, result, latency) {
|
|
716
|
+
console.log(result.labels);
|
|
717
|
+
}
|
|
718
|
+
```
|
|
719
|
+
|
|
676
720
|
**Warning**: The format for `statusCallback` has changed in version 2.0.0 onwards.
|
|
677
721
|
It used to be `statusCallback(latency, result, error)`,
|
|
678
722
|
it has been changed to conform to the usual Node.js standard.
|
|
@@ -690,7 +734,7 @@ The `result` object passed to this callback function has the same fields as the
|
|
|
690
734
|
Example:
|
|
691
735
|
|
|
692
736
|
```javascript
|
|
693
|
-
|
|
737
|
+
function contentInspector(result) {
|
|
694
738
|
if (result.statusCode == 200) {
|
|
695
739
|
const body = JSON.parse(result.body)
|
|
696
740
|
// how to examine the body depends on the content that the service returns
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
declare namespace loadtest {
|
|
2
|
-
export function loadTest(options: LoadTestOptions, err: Function):
|
|
3
|
-
|
|
2
|
+
export function loadTest(options: LoadTestOptions, err: Function): Operation;
|
|
3
|
+
|
|
4
|
+
export interface Operation {
|
|
5
|
+
completedRequests: number
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
export interface LoadTestOptions {
|
|
5
9
|
url: string;
|
|
6
10
|
concurrency?: number;
|
|
@@ -21,6 +25,7 @@ declare namespace loadtest {
|
|
|
21
25
|
secureProtocol?: string;
|
|
22
26
|
statusCallback?(error: Error, result: any, latency: LoadTestResult): void;
|
|
23
27
|
contentInspector?(result: any): void;
|
|
28
|
+
indexParamCallback?(): string;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export interface LoadTestResult {
|
package/lib/httpClient.js
CHANGED
|
@@ -248,14 +248,18 @@ class HttpClient {
|
|
|
248
248
|
callback('Connection ' + id + ' failed: ' + error, '1');
|
|
249
249
|
});
|
|
250
250
|
connection.on('end', () => {
|
|
251
|
+
const client = connection.connection || connection.client
|
|
251
252
|
const result = {
|
|
252
|
-
host:
|
|
253
|
+
host: client._host,
|
|
253
254
|
path: connection.req.path,
|
|
254
255
|
method: connection.req.method,
|
|
255
256
|
statusCode: connection.statusCode,
|
|
256
257
|
body: body,
|
|
257
258
|
headers: connection.headers,
|
|
258
259
|
};
|
|
260
|
+
if (connection.req.labels) {
|
|
261
|
+
result.labels = connection.req.labels
|
|
262
|
+
}
|
|
259
263
|
if (contentInspector) {
|
|
260
264
|
contentInspector(result)
|
|
261
265
|
}
|
package/lib/loadtest.js
CHANGED
|
@@ -88,8 +88,8 @@ let operationInstanceIndex = 0;
|
|
|
88
88
|
*/
|
|
89
89
|
class Operation {
|
|
90
90
|
constructor(options, callback) {
|
|
91
|
-
this.options = options
|
|
92
|
-
this.finalCallback = callback
|
|
91
|
+
this.options = options;
|
|
92
|
+
this.finalCallback = callback;
|
|
93
93
|
this.running = true;
|
|
94
94
|
this.latency = null;
|
|
95
95
|
this.clients = {};
|
|
@@ -110,7 +110,7 @@ class Operation {
|
|
|
110
110
|
this.stopTimeout = setTimeout(() => this.stop(), this.options.maxSeconds * 1000).unref();
|
|
111
111
|
}
|
|
112
112
|
this.showTimer = new HighResolutionTimer(SHOW_INTERVAL_MS, () => this.latency.showPartial());
|
|
113
|
-
this.showTimer.unref()
|
|
113
|
+
this.showTimer.unref();
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
|
@@ -139,14 +139,24 @@ class Operation {
|
|
|
139
139
|
*/
|
|
140
140
|
startClients() {
|
|
141
141
|
const url = this.options.url;
|
|
142
|
+
const strBody = JSON.stringify(this.options.body);
|
|
142
143
|
for (let index = 0; index < this.options.concurrency; index++) {
|
|
143
144
|
if (this.options.indexParam) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
let oldToken = new RegExp(this.options.indexParam, 'g');
|
|
146
|
+
if(this.options.indexParamCallback instanceof Function) {
|
|
147
|
+
let customIndex = this.options.indexParamCallback();
|
|
148
|
+
this.options.url = url.replace(oldToken, customIndex);
|
|
149
|
+
if(this.options.body) {
|
|
150
|
+
let body = strBody.replace(oldToken, customIndex);
|
|
151
|
+
this.options.body = JSON.parse(body);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.options.url = url.replace(oldToken, index);
|
|
156
|
+
if(this.options.body) {
|
|
157
|
+
let body = strBody.replace(oldToken, index);
|
|
158
|
+
this.options.body = JSON.parse(body);
|
|
159
|
+
}
|
|
150
160
|
}
|
|
151
161
|
}
|
|
152
162
|
let constructor = httpClient.create;
|
|
@@ -219,12 +229,66 @@ function testWSEcho(callback) {
|
|
|
219
229
|
exports.loadTest(options, callback);
|
|
220
230
|
}
|
|
221
231
|
|
|
232
|
+
function testIndexParam(callback) {
|
|
233
|
+
const options = {
|
|
234
|
+
url: 'http://localhost:7357/replace',
|
|
235
|
+
concurrency:1,
|
|
236
|
+
quiet: true,
|
|
237
|
+
maxSeconds: 0.1,
|
|
238
|
+
indexParam: "replace"
|
|
239
|
+
};
|
|
240
|
+
exports.loadTest(options, callback);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function testIndexParamWithBody(callback) {
|
|
244
|
+
const options = {
|
|
245
|
+
url: 'http://localhost:7357/replace',
|
|
246
|
+
concurrency:1,
|
|
247
|
+
quiet: true,
|
|
248
|
+
maxSeconds: 0.1,
|
|
249
|
+
indexParam: "replace",
|
|
250
|
+
body: '{"id": "replace"}'
|
|
251
|
+
};
|
|
252
|
+
exports.loadTest(options, callback);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function testIndexParamWithCallback(callback) {
|
|
256
|
+
const options = {
|
|
257
|
+
url: 'http://localhost:7357/replace',
|
|
258
|
+
concurrency:1,
|
|
259
|
+
quiet: true,
|
|
260
|
+
maxSeconds: 0.1,
|
|
261
|
+
indexParam: "replace",
|
|
262
|
+
indexParamCallback: function() {
|
|
263
|
+
//https://gist.github.com/6174/6062387
|
|
264
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
exports.loadTest(options, callback);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function testIndexParamWithCallbackAndBody(callback) {
|
|
271
|
+
const options = {
|
|
272
|
+
url: 'http://localhost:7357/replace',
|
|
273
|
+
concurrency:1,
|
|
274
|
+
quiet: true,
|
|
275
|
+
maxSeconds: 0.1,
|
|
276
|
+
body: '{"id": "replace"}',
|
|
277
|
+
indexParam: "replace",
|
|
278
|
+
indexParamCallback: function() {
|
|
279
|
+
//https://gist.github.com/6174/6062387
|
|
280
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
exports.loadTest(options, callback);
|
|
284
|
+
}
|
|
285
|
+
|
|
222
286
|
|
|
223
287
|
/**
|
|
224
288
|
* Run all tests.
|
|
225
289
|
*/
|
|
226
290
|
exports.test = function(callback) {
|
|
227
|
-
testing.run([testMaxSeconds, testWSEcho], callback);
|
|
291
|
+
testing.run([testMaxSeconds, testWSEcho, testIndexParam, testIndexParamWithBody, testIndexParamWithCallback, testIndexParamWithCallbackAndBody], callback);
|
|
228
292
|
};
|
|
229
293
|
|
|
230
294
|
// run tests if invoked directly
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loadtest",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Run load tests for your web application. Mostly ab-compatible interface, with an option to force requests per second. Includes an API for automated load testing.",
|
|
5
5
|
"homepage": "https://github.com/alexfernandez/loadtest",
|
|
6
6
|
"contributors": [
|