@loadmill/core 0.3.51 → 0.3.54
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 +2 -2
- package/src/conf/defaults.ts +0 -25
- package/src/conf/extrema.ts +0 -36
- package/src/conf/index.ts +0 -95
- package/src/conf/notifications.ts +0 -17
- package/src/conf/types.ts +0 -100
- package/src/conf/validate.ts +0 -559
- package/src/distributed-logger-reporter.ts +0 -19
- package/src/echo/firehose.ts +0 -64
- package/src/echo/index.ts +0 -4
- package/src/echo/stats.ts +0 -84
- package/src/har/index.ts +0 -81
- package/src/multipart-form-data/form-data-utils.ts +0 -81
- package/src/multipart-form-data/is-binary-file.ts +0 -206
- package/src/multipart-form-data/multipart-text-to-post-form-data.ts +0 -149
- package/src/parameters/extractions.ts +0 -53
- package/src/parameters/extractors/cheerio-extractor.ts +0 -57
- package/src/parameters/extractors/expression-extractor.ts +0 -13
- package/src/parameters/extractors/extractor.ts +0 -3
- package/src/parameters/extractors/header-extractor.ts +0 -24
- package/src/parameters/extractors/index.ts +0 -10
- package/src/parameters/extractors/json-path-extractor.ts +0 -63
- package/src/parameters/extractors/parametrized-extractor.ts +0 -27
- package/src/parameters/extractors/regex-extractor.ts +0 -18
- package/src/parameters/extractors/regex-matcher.ts +0 -17
- package/src/parameters/extractors/ws-extractor.ts +0 -91
- package/src/parameters/generate-random.ts +0 -114
- package/src/parameters/index.ts +0 -624
- package/src/parameters/json-path-utils.ts +0 -20
- package/src/parameters/operators/binary-operator.ts +0 -23
- package/src/parameters/operators/index.ts +0 -39
- package/src/parameters/parameter-functions/boolean-parameter-functions.ts +0 -24
- package/src/parameters/parameter-functions/crypto.ts +0 -55
- package/src/parameters/parameter-functions/json-schema.ts +0 -29
- package/src/parameters/parameter-functions/numeric-input-parameter-functions.ts +0 -22
- package/src/parameters/parameter-functions/numeric-parameter-functions.ts +0 -37
- package/src/parameters/parameter-functions/parameter-function-utils.ts +0 -55
- package/src/parameters/parameter-functions/parameter-function.ts +0 -7
- package/src/parameters/parameter-functions/parameter-functions.ts +0 -54
- package/src/parameters/parameter-functions/random-parameter-functions.ts +0 -22
- package/src/parameters/parameter-functions/textual-parameter-functions.ts +0 -464
- package/src/parameters/parameter-regex-providers.ts +0 -78
- package/src/parameters/resolvers/random-parameters-resolver.ts +0 -8
- package/src/parameters/type.ts +0 -7
- package/src/parameters/value-utils.ts +0 -47
- package/src/request/index.ts +0 -526
- package/src/schema/json-schema-generator.ts +0 -76
- package/test/conf/validate.spec.js +0 -141
- package/test/har/is-har.spec.js +0 -33
- package/test/multipart-form-data/form-data-utils.spec.ts +0 -142
- package/test/multipart-form-data/resources/multipart-form-data-file-text-content.json +0 -5
- package/test/parameters/builtin-functions.spec.js +0 -85
- package/test/parameters/json-path-utils.spec.ts +0 -50
- package/test/parameters/parameter-functions.spec.js +0 -48
- package/test/parameters/parameter-utils.spec.js +0 -185
- package/test/parameters/regex-functions.spec.ts +0 -57
- package/test/parameters/value-utils.spec.js +0 -73
- package/test/schema/json-schema-generator.spec.js +0 -227
- package/tsconfig.json +0 -9
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Parameters } from '../type';
|
|
2
|
-
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
3
|
-
|
|
4
|
-
export class ExpressionExtractor extends ParametrizedExtractor {
|
|
5
|
-
constructor(parameters: Parameters) {
|
|
6
|
-
super(parameters);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
extractResolved = (resolvedQuery: string) => {
|
|
10
|
-
// log.debug('Expression extraction resolved:', resolvedQuery);
|
|
11
|
-
return resolvedQuery;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Parameters } from '../type';
|
|
2
|
-
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
3
|
-
|
|
4
|
-
export class HeaderExtractor extends ParametrizedExtractor {
|
|
5
|
-
private headers;
|
|
6
|
-
|
|
7
|
-
constructor(res, parameters: Parameters) {
|
|
8
|
-
super(parameters);
|
|
9
|
-
this.headers = res.header;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
extractResolved = (headerName: string) => {
|
|
13
|
-
const lowerCaseHeaderName = headerName.toLowerCase();
|
|
14
|
-
let headerValue = this.headers[lowerCaseHeaderName];
|
|
15
|
-
|
|
16
|
-
// some servers return more than one 'set-cookie' headers. For extractions we will merge them.
|
|
17
|
-
if (lowerCaseHeaderName === 'set-cookie' && Array.isArray(headerValue)) {
|
|
18
|
-
headerValue = headerValue.join('; ');
|
|
19
|
-
}
|
|
20
|
-
// log.debug('Header extraction:', { headerName, headerValue });
|
|
21
|
-
|
|
22
|
-
return headerValue;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { CheerioExtractor } from './cheerio-extractor';
|
|
2
|
-
import { ExpressionExtractor } from './expression-extractor';
|
|
3
|
-
import { Extractor } from './extractor';
|
|
4
|
-
import { HeaderExtractor } from './header-extractor';
|
|
5
|
-
import { JsonPathExtractor } from './json-path-extractor';
|
|
6
|
-
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
7
|
-
import { RegexExtractor } from './regex-extractor';
|
|
8
|
-
import { WsExtractor } from './ws-extractor';
|
|
9
|
-
|
|
10
|
-
export { CheerioExtractor, ExpressionExtractor, Extractor, HeaderExtractor, JsonPathExtractor, ParametrizedExtractor, RegexExtractor, WsExtractor };
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import jsonpath from 'jsonpath';
|
|
2
|
-
import { Parameters } from '../type';
|
|
3
|
-
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
4
|
-
import { PresentableError } from '@loadmill/universal/dist/errors';
|
|
5
|
-
import log from '@loadmill/universal/dist/log';
|
|
6
|
-
|
|
7
|
-
export class JsonPathExtractor extends ParametrizedExtractor {
|
|
8
|
-
private obj;
|
|
9
|
-
private parseError?;
|
|
10
|
-
|
|
11
|
-
_validateObj = () => {
|
|
12
|
-
const { parseError } = this;
|
|
13
|
-
if (parseError) {
|
|
14
|
-
throw new PresentableError(parseError);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
constructor(target, parameters: Parameters) {
|
|
19
|
-
super(parameters);
|
|
20
|
-
try {
|
|
21
|
-
this.obj = JSON.parse(target);
|
|
22
|
-
} catch (e) {
|
|
23
|
-
this.parseError = e.message || 'Response body is not a valid JSON';
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
extractResolved = (jsonPath: string, full?) => {
|
|
28
|
-
|
|
29
|
-
this._validateObj();
|
|
30
|
-
|
|
31
|
-
let jsonPathResult;
|
|
32
|
-
if (jsonPath === '$') {
|
|
33
|
-
jsonPathResult = this.obj;
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
jsonPathResult = full ? jsonpath.query(this.obj, jsonPath) : jsonpath.value(this.obj, jsonPath);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (jsonPathResult != null) {
|
|
40
|
-
return typeof jsonPathResult === 'object'
|
|
41
|
-
? JSON.stringify(jsonPathResult)
|
|
42
|
-
: jsonPathResult.toString();
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
apply = (jsonPath: string, value) => {
|
|
47
|
-
this._validateObj();
|
|
48
|
-
|
|
49
|
-
log.debug('JSONPath parameter apply:', { jsonPath, value });
|
|
50
|
-
|
|
51
|
-
jsonpath.apply(this.obj, jsonPath, () => {
|
|
52
|
-
try {
|
|
53
|
-
return JSON.parse(value);
|
|
54
|
-
} catch (error) {
|
|
55
|
-
return value;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
log.debug('JSONPath parameter apply result:', { obj: this.obj });
|
|
60
|
-
|
|
61
|
-
return JSON.stringify(this.obj);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Extractor } from './extractor';
|
|
2
|
-
import { parameterUtils } from '../';
|
|
3
|
-
import { Parameters } from '../type';
|
|
4
|
-
|
|
5
|
-
export abstract class ParametrizedExtractor implements Extractor {
|
|
6
|
-
abstract extractResolved: ResolvedExtracter;
|
|
7
|
-
|
|
8
|
-
constructor(private parameters: Parameters) {}
|
|
9
|
-
|
|
10
|
-
extract = (parametrizedQuery: string | string[]) => {
|
|
11
|
-
if (!Array.isArray(parametrizedQuery)) {
|
|
12
|
-
parametrizedQuery = [parametrizedQuery];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const resolvedQuery = parametrizedQuery.map(
|
|
16
|
-
(q) => q && parameterUtils.resolveExpression(q, this.parameters)
|
|
17
|
-
);
|
|
18
|
-
/* log.debug('Parametrized query resolution:', {
|
|
19
|
-
parametrizedQuery,
|
|
20
|
-
resolvedQuery,
|
|
21
|
-
}); */
|
|
22
|
-
|
|
23
|
-
return this.extractResolved(...resolvedQuery);
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type ResolvedExtracter = ((...resolvedQuery: string[]) => string | undefined | Promise<string | undefined>);
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
2
|
-
import { Parameters } from '../type';
|
|
3
|
-
import { matchRegex } from './regex-matcher';
|
|
4
|
-
|
|
5
|
-
export class RegexExtractor extends ParametrizedExtractor {
|
|
6
|
-
constructor(
|
|
7
|
-
private targetProvider: () => string | undefined,
|
|
8
|
-
parameters: Parameters
|
|
9
|
-
) {
|
|
10
|
-
super(parameters);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
extractResolved = (regex: string) => {
|
|
14
|
-
const target = this.targetProvider() || '';
|
|
15
|
-
const regExp = new RegExp(regex);
|
|
16
|
-
return matchRegex(regExp, target);
|
|
17
|
-
};
|
|
18
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import log from '@loadmill/universal/dist/log';
|
|
2
|
-
|
|
3
|
-
const MAX_STR_LENGTH = 500;
|
|
4
|
-
|
|
5
|
-
export const matchRegex = (regExp: RegExp, target: string) => {
|
|
6
|
-
const matchArray = regExp.exec(target);
|
|
7
|
-
|
|
8
|
-
log.debug('Regex parameter extraction:', {
|
|
9
|
-
regExp,
|
|
10
|
-
type: typeof target,
|
|
11
|
-
target: typeof target === 'string' && target.substring(0, MAX_STR_LENGTH),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
if (matchArray && matchArray[1]) {
|
|
15
|
-
return matchArray[1];
|
|
16
|
-
}
|
|
17
|
-
};
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import findLast from 'lodash/findLast';
|
|
2
|
-
import { PresentableError } from '@loadmill/universal/dist/errors';
|
|
3
|
-
import log from '@loadmill/universal/dist/log';
|
|
4
|
-
import { delay } from '@loadmill/universal/dist/promise-utils';
|
|
5
|
-
import { CAPTURE_ALL_REGEX, isCaptureAllRegExp } from '../parameter-regex-providers';
|
|
6
|
-
import { Parameters } from '../type';
|
|
7
|
-
import { ParametrizedExtractor } from './parametrized-extractor';
|
|
8
|
-
import { matchRegex } from './regex-matcher';
|
|
9
|
-
|
|
10
|
-
export class WsExtractor extends ParametrizedExtractor {
|
|
11
|
-
private readonly _messages: string[];
|
|
12
|
-
private readonly _timeLimit: number;
|
|
13
|
-
private _regexp: RegExp;
|
|
14
|
-
constructor(
|
|
15
|
-
extractionData: WSExtractionData = { messages: [], timeLimit: 0 },
|
|
16
|
-
parameters: Parameters,
|
|
17
|
-
) {
|
|
18
|
-
super(parameters);
|
|
19
|
-
this._messages = extractionData.messages;
|
|
20
|
-
this._timeLimit = extractionData.timeLimit;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
extractResolved = async (resolvedRegex: string) => {
|
|
24
|
-
log.debug('Resolved WS extraction regex:', resolvedRegex);
|
|
25
|
-
this._regexp = new RegExp(resolvedRegex || CAPTURE_ALL_REGEX);
|
|
26
|
-
const wsMessage = await this.queryMessage();
|
|
27
|
-
log.debug('WS message queried and found:', wsMessage);
|
|
28
|
-
|
|
29
|
-
return matchRegex(this._regexp, wsMessage);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Querying all received incoming WS messages by regexp.
|
|
34
|
-
* @returns A WS message that satisfies the given regexp. If none found, returns an empty string.
|
|
35
|
-
* @throws RequestFailuresError if the procedure timeouts before any relevant message found.
|
|
36
|
-
*/
|
|
37
|
-
private async queryMessage(): Promise<string> {
|
|
38
|
-
const res = await this.getWSMessageOrTimeout();
|
|
39
|
-
if (!res) {
|
|
40
|
-
throw new PresentableError('Websocket waiting timeout expired');
|
|
41
|
-
}
|
|
42
|
-
return res;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private readonly GIVE_WS_MSG_TIME_MS = 250;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Get an incoming ws message that satisfies the given regex, out of all already received incoming ws messages.
|
|
49
|
-
*
|
|
50
|
-
* If can't find that message, then actively waiting, until procedure timeouts.
|
|
51
|
-
* @param regex To test the messages with
|
|
52
|
-
* @param timeout Milliseconds for the procedure to find a message
|
|
53
|
-
* @returns ws message as string or undefined if timed out
|
|
54
|
-
*/
|
|
55
|
-
private async getWSMessageOrTimeout(): Promise<string | undefined> {
|
|
56
|
-
const startTime = Date.now();
|
|
57
|
-
let message = '';
|
|
58
|
-
let elapsedTime = 0;
|
|
59
|
-
|
|
60
|
-
while (!message && elapsedTime < this._timeLimit) {
|
|
61
|
-
message = this.findMessageByRegex() || '';
|
|
62
|
-
if (message) {
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
await delay(this.GIVE_WS_MSG_TIME_MS);
|
|
67
|
-
elapsedTime = Date.now() - startTime;
|
|
68
|
-
}
|
|
69
|
-
return message;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private findMessageByRegex(): string | undefined {
|
|
73
|
-
if (isCaptureAllRegExp(this._regexp)) {
|
|
74
|
-
return this.getLastMessage();
|
|
75
|
-
}
|
|
76
|
-
return this.findLastMatchingMessage();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private getLastMessage(): string | undefined {
|
|
80
|
-
return this._messages[this._messages.length - 1];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private findLastMatchingMessage(): string | undefined {
|
|
84
|
-
return findLast(this._messages, msg => this._regexp.test(msg));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export type WSExtractionData = {
|
|
89
|
-
messages: string[];
|
|
90
|
-
timeLimit: number;
|
|
91
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import uuid from 'uuid';
|
|
2
|
-
import randomstring from 'randomstring';
|
|
3
|
-
import clamp = require('lodash/clamp');
|
|
4
|
-
import random = require('lodash/random');
|
|
5
|
-
import { parameterValueToNumber } from './value-utils';
|
|
6
|
-
import { PresentableError } from '@loadmill/universal/dist/errors';
|
|
7
|
-
|
|
8
|
-
const MAX_RANDOM_LEN = 100;
|
|
9
|
-
const DEFAULT_RANDOM_LEN = 10;
|
|
10
|
-
// 2^32
|
|
11
|
-
const DEFAULT_MAX_RANDOM_INT = 4294967296;
|
|
12
|
-
|
|
13
|
-
export enum RandomTypes {
|
|
14
|
-
hex = 'hex',
|
|
15
|
-
uuid = 'uuid',
|
|
16
|
-
from = 'from',
|
|
17
|
-
chars = 'chars',
|
|
18
|
-
number = 'number',
|
|
19
|
-
digits = 'digits',
|
|
20
|
-
uppers = 'uppers',
|
|
21
|
-
lowers = 'lowers',
|
|
22
|
-
letters = 'letters',
|
|
23
|
-
boolean = 'boolean',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function generateRandom(kind: string, arg1?: string, arg2?: string) {
|
|
27
|
-
if (!kind) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (kind === RandomTypes.uuid) {
|
|
32
|
-
return uuid.v4();
|
|
33
|
-
} else if (kind === RandomTypes.number) {
|
|
34
|
-
let min = 0,
|
|
35
|
-
max = DEFAULT_MAX_RANDOM_INT;
|
|
36
|
-
|
|
37
|
-
if (arg2) {
|
|
38
|
-
min = nonNegativeInt(arg1);
|
|
39
|
-
max = nonNegativeInt(arg2);
|
|
40
|
-
|
|
41
|
-
if (min > max) {
|
|
42
|
-
const temp = min;
|
|
43
|
-
min = max;
|
|
44
|
-
max = temp;
|
|
45
|
-
}
|
|
46
|
-
} else if (arg1) {
|
|
47
|
-
max = nonNegativeInt(arg1);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Assumes both are integers!
|
|
51
|
-
return random(min, max);
|
|
52
|
-
} else if (kind === RandomTypes.boolean) {
|
|
53
|
-
const probability = nonNegativeInt(arg1, 50) / 100;
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
probability >= 1 ||
|
|
57
|
-
(probability !== 0 && Math.random() <= probability)
|
|
58
|
-
).toString();
|
|
59
|
-
} else {
|
|
60
|
-
const length = nonNegativeInt(
|
|
61
|
-
kind === RandomTypes.from ? arg2 : arg1,
|
|
62
|
-
DEFAULT_RANDOM_LEN
|
|
63
|
-
);
|
|
64
|
-
const options: { length; charset?; capitalization? } = {
|
|
65
|
-
length: clamp(length, 0, MAX_RANDOM_LEN),
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
if (kind === RandomTypes.chars) {
|
|
69
|
-
options.charset = 'alphanumeric';
|
|
70
|
-
} else if (kind === RandomTypes.digits) {
|
|
71
|
-
options.charset = 'numeric';
|
|
72
|
-
} else if (kind === RandomTypes.hex) {
|
|
73
|
-
options.charset = 'hex';
|
|
74
|
-
} else if (
|
|
75
|
-
kind === RandomTypes.letters ||
|
|
76
|
-
kind === RandomTypes.lowers ||
|
|
77
|
-
kind === RandomTypes.uppers
|
|
78
|
-
) {
|
|
79
|
-
options.charset = 'alphabetic';
|
|
80
|
-
|
|
81
|
-
if (kind !== RandomTypes.letters) {
|
|
82
|
-
options.capitalization =
|
|
83
|
-
kind === RandomTypes.lowers ? 'lowercase' : 'uppercase';
|
|
84
|
-
}
|
|
85
|
-
} else if (kind === RandomTypes.from) {
|
|
86
|
-
if (!arg1) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
options.charset = arg1;
|
|
90
|
-
} else {
|
|
91
|
-
options.charset = kind;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return randomstring.generate(options);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function nonNegativeInt(arg?: string, def?: number) {
|
|
99
|
-
let value;
|
|
100
|
-
|
|
101
|
-
if (!arg) {
|
|
102
|
-
value = def;
|
|
103
|
-
} else {
|
|
104
|
-
value = parameterValueToNumber(arg, { integer: true, nonNegative: true });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (value == null) {
|
|
108
|
-
throw new PresentableError(
|
|
109
|
-
'Argument must be a non-negative integer, instead found: ' + arg
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return value;
|
|
114
|
-
}
|