@artilleryio/int-core 2.2.1 → 2.2.2-572880f
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/package.json +3 -3
- package/lib/#engine_ws.js# +0 -366
- package/lib/.engine_http.js.~undo-tree~ +0 -10
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artilleryio/int-core",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2-572880f",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@artilleryio/int-commons": "
|
|
7
|
+
"@artilleryio/int-commons": "2.0.4-572880f",
|
|
8
8
|
"@artilleryio/sketches-js": "^2.1.1",
|
|
9
9
|
"agentkeepalive": "^4.1.0",
|
|
10
10
|
"arrivals": "^2.1.2",
|
|
@@ -53,4 +53,4 @@
|
|
|
53
53
|
"socket.io": "^4.7.1",
|
|
54
54
|
"tap": "^16.3.7"
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
}
|
package/lib/#engine_ws.js#
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
og/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const async = require('async');
|
|
8
|
-
const _ = require('lodash');
|
|
9
|
-
const WebSocket = require('ws');
|
|
10
|
-
const HttpsProxyAgent = require('https-proxy-agent');
|
|
11
|
-
const debug = require('debug')('ws');
|
|
12
|
-
const url = require('url');
|
|
13
|
-
const engineUtil = require('@artilleryio/int-commons').engine_util;
|
|
14
|
-
const template = engineUtil.template;
|
|
15
|
-
|
|
16
|
-
module.exports = WSEngine;
|
|
17
|
-
|
|
18
|
-
function WSEngine(script) {
|
|
19
|
-
this.config = script.config;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
WSEngine.prototype.createScenario = function (scenarioSpec, ee) {
|
|
23
|
-
const self = this;
|
|
24
|
-
const tasks = _.map(scenarioSpec.flow, function (rs) {
|
|
25
|
-
if (typeof rs.think !== 'undefined') {
|
|
26
|
-
return engineUtil.createThink(
|
|
27
|
-
rs,
|
|
28
|
-
_.get(self.config, 'defaults.think', {})
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return self.step(rs, ee);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return self.compile(tasks, scenarioSpec.flow, ee);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
function getMessageHandler(context, params, ee, timeout, callback) {
|
|
39
|
-
let done = false;
|
|
40
|
-
|
|
41
|
-
setTimeout(() => {
|
|
42
|
-
if (!done) {
|
|
43
|
-
const err = 'response timeout';
|
|
44
|
-
ee.emit('error', err);
|
|
45
|
-
return callback(err, context);
|
|
46
|
-
}
|
|
47
|
-
}, timeout * 1000);
|
|
48
|
-
|
|
49
|
-
return function messageHandler(event) {
|
|
50
|
-
ee.emit('counter', 'websocket.messages_received', 1);
|
|
51
|
-
ee.emit('rate', 'websocket.receive_rate');
|
|
52
|
-
done = true;
|
|
53
|
-
const { data } = event;
|
|
54
|
-
|
|
55
|
-
debug('WS receive: %s', data);
|
|
56
|
-
|
|
57
|
-
if (!data) {
|
|
58
|
-
return callback(new Error('Empty response from WS server'), context);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let fauxResponse;
|
|
62
|
-
try {
|
|
63
|
-
fauxResponse = { body: JSON.parse(data) };
|
|
64
|
-
} catch (err) {
|
|
65
|
-
fauxResponse = { body: event.data };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
engineUtil.captureOrMatch(
|
|
69
|
-
params,
|
|
70
|
-
fauxResponse,
|
|
71
|
-
context,
|
|
72
|
-
function captured(err, result) {
|
|
73
|
-
if (err) {
|
|
74
|
-
ee.emit('error', err.message || err.code);
|
|
75
|
-
return callback(err, context);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const { captures = {}, matches = {} } = result;
|
|
79
|
-
|
|
80
|
-
debug('matches: ', matches);
|
|
81
|
-
debug('captures: ', captures);
|
|
82
|
-
|
|
83
|
-
// match and capture are strict by default:
|
|
84
|
-
const haveFailedMatches = _.some(result.matches, function (v) {
|
|
85
|
-
return !v.success && v.strict !== false;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const haveFailedCaptures = _.some(result.captures, function (v) {
|
|
89
|
-
return v.failed;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
if (haveFailedMatches || haveFailedCaptures) {
|
|
93
|
-
// TODO: Emit the details of each failed capture/match
|
|
94
|
-
return callback(new Error('Failed capture or match'), context);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
_.each(result.matches, function (v) {
|
|
98
|
-
ee.emit('match', v.success, {
|
|
99
|
-
expected: v.expected,
|
|
100
|
-
got: v.got,
|
|
101
|
-
expression: v.expression,
|
|
102
|
-
strict: v.strict
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
_.each(result.captures, function (v, k) {
|
|
107
|
-
_.set(context.vars, k, v.value);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return callback(null, context);
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
WSEngine.prototype.step = function (requestSpec, ee) {
|
|
117
|
-
const self = this;
|
|
118
|
-
|
|
119
|
-
if (requestSpec.loop) {
|
|
120
|
-
const steps = _.map(requestSpec.loop, function (rs) {
|
|
121
|
-
return self.step(rs, ee);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
return engineUtil.createLoopWithCount(requestSpec.count || -1, steps, {
|
|
125
|
-
loopValue: requestSpec.loopValue || '$loopCount',
|
|
126
|
-
overValues: requestSpec.over,
|
|
127
|
-
whileTrue: self.config.processor
|
|
128
|
-
? self.config.processor[requestSpec.whileTrue]
|
|
129
|
-
: undefined
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (requestSpec.think) {
|
|
134
|
-
return engineUtil.createThink(
|
|
135
|
-
requestSpec,
|
|
136
|
-
_.get(self.config, 'defaults.think', {})
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (requestSpec.function) {
|
|
141
|
-
return function (context, callback) {
|
|
142
|
-
const processFunc = self.config.processor[requestSpec.function];
|
|
143
|
-
if (processFunc) {
|
|
144
|
-
processFunc(context, ee, function () {
|
|
145
|
-
return callback(null, context);
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (requestSpec.log) {
|
|
152
|
-
return function (context, callback) {
|
|
153
|
-
console.log(template(requestSpec.log, context));
|
|
154
|
-
return process.nextTick(function () {
|
|
155
|
-
callback(null, context);
|
|
156
|
-
});
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (requestSpec.connect) {
|
|
161
|
-
return function (context, callback) {
|
|
162
|
-
return process.nextTick(function () {
|
|
163
|
-
callback(null, context);
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const f = function (context, callback) {
|
|
169
|
-
const params = requestSpec.wait || requestSpec.send;
|
|
170
|
-
|
|
171
|
-
// match exists on a string, so check match is not a prototype
|
|
172
|
-
let captureOrMatch = _.has(params, 'capture') || _.has(params, 'match');
|
|
173
|
-
|
|
174
|
-
if (captureOrMatch) {
|
|
175
|
-
// only process response if we're capturing
|
|
176
|
-
let timeout =
|
|
177
|
-
self.config.timeout || _.get(self.config, 'ws.timeout') || 10;
|
|
178
|
-
context.ws.onmessage = getMessageHandler(
|
|
179
|
-
context,
|
|
180
|
-
params,
|
|
181
|
-
ee,
|
|
182
|
-
timeout,
|
|
183
|
-
callback
|
|
184
|
-
);
|
|
185
|
-
} else {
|
|
186
|
-
// Reset onmessage to stop steps interfering with each other
|
|
187
|
-
context.ws.onmessage = undefined;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Backwards compatible with previous version of `send` api
|
|
191
|
-
let payload = captureOrMatch ? params.payload : params;
|
|
192
|
-
|
|
193
|
-
if (payload !== undefined) {
|
|
194
|
-
payload = template(payload, context);
|
|
195
|
-
if (typeof payload === 'object') {
|
|
196
|
-
payload = JSON.stringify(payload);
|
|
197
|
-
} else {
|
|
198
|
-
payload = _.toString(payload);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
ee.emit('counter', 'websocket.messages_sent', 1);
|
|
202
|
-
ee.emit('rate', 'websocket.send_rate');
|
|
203
|
-
debug('WS send: %s', payload);
|
|
204
|
-
|
|
205
|
-
context.ws.send(payload, function (err) {
|
|
206
|
-
if (err) {
|
|
207
|
-
debug(err);
|
|
208
|
-
ee.emit('error', err);
|
|
209
|
-
return callback(err, null);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// End step if we're not capturing
|
|
213
|
-
if (!captureOrMatch) {
|
|
214
|
-
return callback(null, context);
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
} else if (captureOrMatch) {
|
|
218
|
-
debug('WS wait: %j', params);
|
|
219
|
-
} else {
|
|
220
|
-
// in the end, we could not send anything, so report it and stop
|
|
221
|
-
let err = 'invalid_step';
|
|
222
|
-
debug(err, requestSpec);
|
|
223
|
-
ee.emit('error', err);
|
|
224
|
-
return callback(err, context);
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
return f;
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
function getWsOptions(config) {
|
|
232
|
-
const options = getWsConfig(config);
|
|
233
|
-
const subprotocols = _.get(config, 'ws.subprotocols', []);
|
|
234
|
-
const headers = _.get(config, 'ws.headers', {});
|
|
235
|
-
|
|
236
|
-
const subprotocolHeader = _.find(headers, (value, headerName) => {
|
|
237
|
-
return headerName.toLowerCase() === 'sec-websocket-protocol';
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
if (typeof subprotocolHeader !== 'undefined') {
|
|
241
|
-
// NOTE: subprotocols defined via config.ws.subprotocols take precedence:
|
|
242
|
-
subprotocols.push(...subprotocolHeader.split(',').map((s) => s.trim()));
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return { options, subprotocols };
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function getWsInstance(config, scenarioSpec, context, cb) {
|
|
249
|
-
let wsArgs = {
|
|
250
|
-
...getWsOptions(config),
|
|
251
|
-
target: config.target
|
|
252
|
-
};
|
|
253
|
-
const [{ connect }] = scenarioSpec;
|
|
254
|
-
|
|
255
|
-
if (connect) {
|
|
256
|
-
if (connect.function && config.processor[connect.function]) {
|
|
257
|
-
const processFn = config.processor[connect.function];
|
|
258
|
-
|
|
259
|
-
return processFn(wsArgs, context, (err) => {
|
|
260
|
-
if (err) {
|
|
261
|
-
debug('connect.function', err);
|
|
262
|
-
return cb(err, null);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
context.wsArgs = wsArgs;
|
|
266
|
-
|
|
267
|
-
return cb(null, context);
|
|
268
|
-
});
|
|
269
|
-
} else if (_.isPlainObject(connect)) {
|
|
270
|
-
const {
|
|
271
|
-
target = config.target,
|
|
272
|
-
headers = _.get(config, 'ws.headers', {}),
|
|
273
|
-
subprotocols = _.get(config, 'ws.subprotocols', []),
|
|
274
|
-
...instanceConfig
|
|
275
|
-
} = connect;
|
|
276
|
-
|
|
277
|
-
const opt = getWsOptions({
|
|
278
|
-
tls: config.tls,
|
|
279
|
-
ws: { subprotocols, headers, ...instanceConfig }
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
wsArgs = {
|
|
283
|
-
target: template(target, context),
|
|
284
|
-
...opt
|
|
285
|
-
};
|
|
286
|
-
} else {
|
|
287
|
-
wsArgs.target = template(connect, context);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
debug('new WebSocket instance:', wsArgs);
|
|
292
|
-
|
|
293
|
-
context.wsArgs = wsArgs;
|
|
294
|
-
|
|
295
|
-
return cb(null, context);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
WSEngine.prototype.compile = function (tasks, scenarioSpec, ee) {
|
|
299
|
-
const config = this.config;
|
|
300
|
-
|
|
301
|
-
return function scenario(initialContext, callback) {
|
|
302
|
-
function zero(cb) {
|
|
303
|
-
ee.emit('started');
|
|
304
|
-
|
|
305
|
-
getWsInstance(config, scenarioSpec, initialContext, cb);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function one(context, cb) {
|
|
309
|
-
const { wsArgs, ...contextWithoutWsArgs } = context;
|
|
310
|
-
const ws = new WebSocket(
|
|
311
|
-
wsArgs.target,
|
|
312
|
-
wsArgs.subprotocols,
|
|
313
|
-
wsArgs.options
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
ws.on('open', function () {
|
|
317
|
-
contextWithoutWsArgs.ws = ws;
|
|
318
|
-
|
|
319
|
-
return cb(null, contextWithoutWsArgs);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
ws.once('error', function (err) {
|
|
323
|
-
debug(err);
|
|
324
|
-
ee.emit('error', err.message || err.code);
|
|
325
|
-
|
|
326
|
-
return cb(err, {});
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
initialContext._successCount = 0;
|
|
331
|
-
|
|
332
|
-
const steps = _.flatten([zero, one, tasks]);
|
|
333
|
-
|
|
334
|
-
async.waterfall(steps, function scenarioWaterfallCb(err, context) {
|
|
335
|
-
if (err) {
|
|
336
|
-
debug(err);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (context && context.ws) {
|
|
340
|
-
context.ws.close();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return callback(err, context);
|
|
344
|
-
});
|
|
345
|
-
};
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
function getWsConfig(config) {
|
|
349
|
-
const tls = config.tls || {};
|
|
350
|
-
const { proxy, ...options } = config.ws || {};
|
|
351
|
-
|
|
352
|
-
if (proxy) {
|
|
353
|
-
const { url: proxyUrl, ...proxyOptions } = proxy;
|
|
354
|
-
|
|
355
|
-
debug('Set proxy: %s, options: %s', proxyUrl, proxyOptions);
|
|
356
|
-
|
|
357
|
-
const agent = new HttpsProxyAgent({
|
|
358
|
-
...url.parse(proxyUrl),
|
|
359
|
-
...proxyOptions
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
options.agent = agent;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
return _.extend(tls, options);
|
|
366
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
(undo-tree-save-format-version . 1)
|
|
2
|
-
"545a0b3c114a212400ccd5c49280fc85dc34e487"
|
|
3
|
-
[nil nil nil nil (25818 13444 881901 0) 0 nil]
|
|
4
|
-
([nil nil ((10895 . 10897) (t 25767 49356 0 0)) nil (25818 13444 881900 0) 0 nil])
|
|
5
|
-
([nil nil ((#("e" 0 1 (fontified t)) . -10896) (undo-tree-id0 . -1) (undo-tree-id1 . -1) 10897) nil (25818 13444 881899 0) 0 nil])
|
|
6
|
-
([nil nil ((10896 . 10915)) nil (25818 13444 881892 0) 0 nil])
|
|
7
|
-
([nil current ((10943 . 10944)) nil (25818 13444 881956 0) 0 nil])
|
|
8
|
-
([nil nil ((10866 . 10868) (10944 . 10957)) ((#("
|
|
9
|
-
" 0 1 (fontified nil) 1 13 (fontified t)) . 10944) (undo-tree-id2 . -1) (#(" " 0 2 (fontified t)) . 10866)) (25818 13444 881888 0) 0 nil])
|
|
10
|
-
nil
|