loadtest 8.0.7 → 8.1.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/.loadtestrc +2 -0
- package/doc/api.md +2 -1
- package/lib/headers.js +12 -7
- package/lib/httpClient.js +4 -4
- package/lib/options.js +4 -4
- package/lib/pool.js +1 -2
- package/lib/websocket.js +9 -6
- package/package.json +1 -1
- package/test/headers.js +5 -3
package/.loadtestrc
ADDED
package/doc/api.md
CHANGED
|
@@ -109,7 +109,8 @@ An array of cookies to send. Each cookie should be a string of the form `name=va
|
|
|
109
109
|
|
|
110
110
|
#### `headers`
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
An object containing headers of the form `key: 'value'}.
|
|
113
|
+
Each attribute of the object should be a header with the value given as a string.
|
|
113
114
|
If you want to have several values for a header, write a single value separated by semicolons,
|
|
114
115
|
like this:
|
|
115
116
|
|
package/lib/headers.js
CHANGED
|
@@ -6,25 +6,30 @@
|
|
|
6
6
|
export function addHeaders(rawHeaders, headers) {
|
|
7
7
|
if (Array.isArray(rawHeaders)) {
|
|
8
8
|
rawHeaders.forEach(function(header) {
|
|
9
|
-
|
|
9
|
+
addTextHeader(header, headers);
|
|
10
10
|
});
|
|
11
11
|
} else if (typeof rawHeaders == 'string') {
|
|
12
|
-
|
|
12
|
+
addTextHeader(rawHeaders, headers);
|
|
13
|
+
} else if (typeof rawHeaders == 'object') {
|
|
14
|
+
for (const key of Object.keys(rawHeaders)) {
|
|
15
|
+
addHeader(key, rawHeaders[key], headers)
|
|
16
|
+
}
|
|
13
17
|
} else {
|
|
14
18
|
console.error('Invalid header structure %j, it should be an array', rawHeaders);
|
|
15
19
|
}
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
* Add a single header to an array.
|
|
20
|
-
*/
|
|
21
|
-
function addHeader(rawHeader, headers) {
|
|
22
|
+
function addTextHeader(rawHeader, headers) {
|
|
22
23
|
if (!rawHeader.includes(':')) {
|
|
23
24
|
return console.error('Invalid header %s, it should be in the form -H key:value', rawHeader);
|
|
24
25
|
}
|
|
25
26
|
const index = rawHeader.indexOf(':');
|
|
26
27
|
const key = rawHeader.substr(0, index);
|
|
27
28
|
const value = rawHeader.substr(index + 1);
|
|
29
|
+
addHeader(key, value, headers)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function addHeader(key, value, headers) {
|
|
28
33
|
headers[key.toLowerCase()] = value;
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -33,7 +38,7 @@ function addHeader(rawHeader, headers) {
|
|
|
33
38
|
*/
|
|
34
39
|
export function addUserAgent(headers) {
|
|
35
40
|
if(!headers['user-agent']) {
|
|
36
|
-
|
|
41
|
+
addHeader('user-agent', 'node.js loadtest bot', headers)
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
44
|
|
package/lib/httpClient.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as http from 'http'
|
|
|
3
3
|
import * as https from 'https'
|
|
4
4
|
import * as querystring from 'querystring'
|
|
5
5
|
import * as websocket from 'websocket'
|
|
6
|
-
import {addUserAgent} from './headers.js'
|
|
6
|
+
import { addUserAgent } from './headers.js'
|
|
7
7
|
import * as agentkeepalive from 'agentkeepalive'
|
|
8
8
|
import * as HttpsProxyAgent from 'https-proxy-agent'
|
|
9
9
|
|
|
@@ -68,7 +68,7 @@ export class HttpClient {
|
|
|
68
68
|
}
|
|
69
69
|
if (this.options.cookies) {
|
|
70
70
|
if (Array.isArray(this.options.cookies)) {
|
|
71
|
-
this.params.headers.Cookie =
|
|
71
|
+
this.params.headers.Cookie = this.options.cookies.join('; ');
|
|
72
72
|
} else if (typeof this.options.cookies == 'string') {
|
|
73
73
|
this.params.headers.Cookie = this.options.cookies;
|
|
74
74
|
} else {
|
|
@@ -119,7 +119,7 @@ export class HttpClient {
|
|
|
119
119
|
return
|
|
120
120
|
}
|
|
121
121
|
const id = this.latency.begin();
|
|
122
|
-
const params = {...this.params, headers: {...this.params.headers}}
|
|
122
|
+
const params = { ...this.params, headers: { ...this.params.headers } }
|
|
123
123
|
this.customizeIndex(params)
|
|
124
124
|
const request = this.getRequest(id, params)
|
|
125
125
|
if (this.options.timeout) {
|
|
@@ -183,7 +183,7 @@ export class HttpClient {
|
|
|
183
183
|
if (this.params.protocol == 'https:') {
|
|
184
184
|
return https;
|
|
185
185
|
}
|
|
186
|
-
if (this.params.protocol == 'ws:') {
|
|
186
|
+
if (this.params.protocol == 'ws:' || this.params.protocol == 'wss:') {
|
|
187
187
|
return websocket;
|
|
188
188
|
}
|
|
189
189
|
return http;
|
package/lib/options.js
CHANGED
|
@@ -56,10 +56,10 @@ class Options {
|
|
|
56
56
|
if (!options.url) {
|
|
57
57
|
throw new Error('Missing URL in options')
|
|
58
58
|
}
|
|
59
|
-
if (!options.url.startsWith('http://') && !options.url.startsWith('https://') && !options.url.startsWith('ws://')) {
|
|
60
|
-
throw new Error(`Invalid URL ${options.url}, must be http://, https
|
|
59
|
+
if (!options.url.startsWith('http://') && !options.url.startsWith('https://') && !options.url.startsWith('ws://') && !options.url.startsWith('wss://')) {
|
|
60
|
+
throw new Error(`Invalid URL ${options.url}, must be http://, https://, ws://, or wss://'`)
|
|
61
61
|
}
|
|
62
|
-
if (options.url.startsWith('ws:')) {
|
|
62
|
+
if (options.url.startsWith('ws:') || options.url.startsWith('wss:')) {
|
|
63
63
|
if (options.requestsPerSecond) {
|
|
64
64
|
throw new Error(`"requestsPerSecond" not supported for WebSockets`);
|
|
65
65
|
}
|
|
@@ -118,7 +118,7 @@ class Options {
|
|
|
118
118
|
if (this.certFile) {
|
|
119
119
|
this.cert = await readFile(this.certFile);
|
|
120
120
|
}
|
|
121
|
-
if (typeof this.requestGenerator == 'string') {
|
|
121
|
+
if (this.requestGenerator && typeof this.requestGenerator == 'string') {
|
|
122
122
|
this.requestGenerator = await import(this.requestGenerator)
|
|
123
123
|
}
|
|
124
124
|
if (this.bodyFile) {
|
package/lib/pool.js
CHANGED
|
@@ -46,8 +46,7 @@ export class Pool {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
createClient() {
|
|
49
|
-
|
|
50
|
-
if (this.options.url.startsWith('ws:')) {
|
|
49
|
+
if (this.options.url.startsWith('ws:') || this.options.url.startsWith('wss:')) {
|
|
51
50
|
return new WebsocketClient(this.loadTest)
|
|
52
51
|
}
|
|
53
52
|
if (this.options.tcp) {
|
package/lib/websocket.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import websocket from 'websocket'
|
|
2
|
-
import {BaseClient} from './baseClient.js'
|
|
2
|
+
import { BaseClient } from './baseClient.js'
|
|
3
3
|
|
|
4
4
|
let latency;
|
|
5
5
|
|
|
@@ -21,10 +21,13 @@ export class WebsocketClient extends BaseClient {
|
|
|
21
21
|
* Start the websocket client.
|
|
22
22
|
*/
|
|
23
23
|
start() {
|
|
24
|
-
this.client = new websocket.client();
|
|
25
|
-
this.client.on('connectFailed', () => {});
|
|
24
|
+
this.client = new websocket.client({ rejectUnauthorized: false });
|
|
25
|
+
this.client.on('connectFailed', (e) => console.error(`Websocket connection error: ${e.message}`));
|
|
26
26
|
this.client.on('connect', connection => this.connect(connection));
|
|
27
|
-
|
|
27
|
+
if (this.options.insecure)
|
|
28
|
+
this.client.connect(this.options.url, undefined, undefined, undefined, { "rejectUnauthorized": false });
|
|
29
|
+
else
|
|
30
|
+
this.client.connect(this.options.url);
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
/**
|
|
@@ -84,7 +87,7 @@ export class WebsocketClient extends BaseClient {
|
|
|
84
87
|
try {
|
|
85
88
|
json = JSON.parse(message.utf8Data);
|
|
86
89
|
}
|
|
87
|
-
catch(e) {
|
|
90
|
+
catch (e) {
|
|
88
91
|
console.error('Invalid JSON: ' + message.utf8Data);
|
|
89
92
|
return;
|
|
90
93
|
}
|
|
@@ -104,7 +107,7 @@ export class WebsocketClient extends BaseClient {
|
|
|
104
107
|
requestFinished(null, json);
|
|
105
108
|
});
|
|
106
109
|
|
|
107
|
-
let message={some:"message"};
|
|
110
|
+
let message = { some: "message" };
|
|
108
111
|
|
|
109
112
|
if (this.generateMessage) {
|
|
110
113
|
message = this.generateMessage(id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loadtest",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"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.",
|
|
6
6
|
"homepage": "https://github.com/alexfernandez/loadtest",
|
package/test/headers.js
CHANGED
|
@@ -3,7 +3,7 @@ import {addHeaders, addUserAgent} from '../lib/headers.js'
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
function testAddHeaders(callback) {
|
|
6
|
-
const tests = [
|
|
6
|
+
const tests = [{
|
|
7
7
|
raw: 'k:v',
|
|
8
8
|
headers: { 'k': 'v' }
|
|
9
9
|
}, {
|
|
@@ -18,8 +18,10 @@ function testAddHeaders(callback) {
|
|
|
18
18
|
}, {
|
|
19
19
|
raw: 'k:v:w',
|
|
20
20
|
headers: { 'k': 'v:w' }
|
|
21
|
-
}
|
|
22
|
-
|
|
21
|
+
}, {
|
|
22
|
+
raw: {accept: 'text/plain;text/html'},
|
|
23
|
+
headers: {accept: 'text/plain;text/html'},
|
|
24
|
+
}];
|
|
23
25
|
tests.forEach(function(test) {
|
|
24
26
|
const headers = {};
|
|
25
27
|
addHeaders(test.raw, headers);
|