@loadmill/executer 0.1.50 → 0.1.53
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/dist/extraction-combiner.js +6 -6
- package/dist/extraction-combiner.js.map +1 -1
- package/dist/mill-info.d.ts +4 -0
- package/dist/mill-version.js +1 -1
- package/dist/post-script/console-log.d.ts +7 -0
- package/dist/post-script/console-log.js +31 -0
- package/dist/post-script/console-log.js.map +1 -0
- package/dist/post-script/post-script-executor.js +7 -4
- package/dist/post-script/post-script-executor.js.map +1 -1
- package/dist/request-sequence-result.d.ts +1 -0
- package/dist/sequence.d.ts +1 -1
- package/dist/sequence.js +18 -8
- package/dist/sequence.js.map +1 -1
- package/dist/single-runner.d.ts +1 -0
- package/dist/single-runner.js +1 -1
- package/dist/single-runner.js.map +1 -1
- package/package.json +3 -3
- package/src/asserter.ts +0 -137
- package/src/errors.ts +0 -10
- package/src/extraction-combiner.ts +0 -110
- package/src/failures.ts +0 -79
- package/src/message-creators.ts +0 -44
- package/src/mill-info.ts +0 -76
- package/src/mill-version.ts +0 -7
- package/src/post-script/ast-walker/index.ts +0 -160
- package/src/post-script/ast-walker/type-guard.ts +0 -73
- package/src/post-script/ast-walker/types.ts +0 -35
- package/src/post-script/parser/acorn-js-parser.ts +0 -8
- package/src/post-script/parser/js-parser.ts +0 -22
- package/src/post-script/parser/parser.ts +0 -5
- package/src/post-script/post-script-executor.ts +0 -89
- package/src/post-script/virtual-machine/virtual-machine.ts +0 -15
- package/src/post-script/virtual-machine/vm2-virtual-machine.ts +0 -45
- package/src/report-types.ts +0 -127
- package/src/request-sequence-result.ts +0 -63
- package/src/request-stats.ts +0 -20
- package/src/res-keeper.ts +0 -53
- package/src/sampler.ts +0 -133
- package/src/sequence.ts +0 -1107
- package/src/single-runner.ts +0 -66
- package/src/test-run-event-emitter.ts +0 -25
- package/src/utils.ts +0 -8
- package/src/work.ts +0 -17
- package/src/ws.ts +0 -286
- package/test/post-script-executor.spec.ts +0 -677
- package/tsconfig.json +0 -9
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from 'assert';
|
|
2
|
-
import { SequenceExecutorParameters } from '@loadmill/core/dist/parameters';
|
|
3
|
-
import { ParameterFunctionOperations } from '@loadmill/core/dist/parameters/parameter-functions/parameter-functions';
|
|
4
|
-
import { ASTWalker } from './ast-walker';
|
|
5
|
-
import { VM2VirtualMachine } from './virtual-machine/vm2-virtual-machine';
|
|
6
|
-
|
|
7
|
-
export class PostScriptRunner {
|
|
8
|
-
public run = (
|
|
9
|
-
staticContext: OuterStaticContext = { staticContext: { $: {}, __: {} } },
|
|
10
|
-
dynamicContext: SequenceExecutorParameters = {},
|
|
11
|
-
userCode: string = ''
|
|
12
|
-
): SequenceExecutorParameters => {
|
|
13
|
-
const newVariables = new ASTWalker(userCode).detectDeclarations(Object.keys(staticContext));
|
|
14
|
-
const wrappedUserCode = this.wrapUserCode(dynamicContext, userCode, newVariables);
|
|
15
|
-
const vm = new VM2VirtualMachine();
|
|
16
|
-
vm.create({
|
|
17
|
-
globalObject: { assert, ...dynamicContext },
|
|
18
|
-
staticObject: staticContext,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const modifiedDynamicContext = vm.run(wrappedUserCode);
|
|
22
|
-
this.validateCircularDependency(modifiedDynamicContext);
|
|
23
|
-
this.removeAssertModule(modifiedDynamicContext);
|
|
24
|
-
return modifiedDynamicContext;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
private wrapUserCode = (
|
|
28
|
-
dynamicContext: SequenceExecutorParameters = {},
|
|
29
|
-
userCode: string = '',
|
|
30
|
-
newVariables: string[] = []
|
|
31
|
-
) => {
|
|
32
|
-
const prefix =
|
|
33
|
-
`
|
|
34
|
-
Buffer = {};
|
|
35
|
-
global = { assert: global.assert };
|
|
36
|
-
const $ = staticContext.$;
|
|
37
|
-
const __ = staticContext.__;
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
const suffix =
|
|
41
|
-
`
|
|
42
|
-
exports = {
|
|
43
|
-
${[...Object.keys(dynamicContext), ...newVariables].join()}
|
|
44
|
-
};
|
|
45
|
-
`;
|
|
46
|
-
|
|
47
|
-
return prefix + userCode + suffix;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
validateCircularDependency = (obj: SequenceExecutorParameters) => {
|
|
51
|
-
function circularError (propName: string) {
|
|
52
|
-
return new TypeError(`Cyclic object value. Circular reference in property ${propName}`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
findCircular(obj);
|
|
56
|
-
|
|
57
|
-
function findCircular(
|
|
58
|
-
obj: SequenceExecutorParameters,
|
|
59
|
-
_refs: WeakSet<SequenceExecutorParameters> = new WeakSet()
|
|
60
|
-
) {
|
|
61
|
-
if (typeof obj === 'object' && obj !== null) {
|
|
62
|
-
_refs.add(obj);
|
|
63
|
-
for (const key in obj) {
|
|
64
|
-
if (_refs.has(obj[key])) {
|
|
65
|
-
throw circularError(key);
|
|
66
|
-
}
|
|
67
|
-
findCircular(obj[key], _refs);
|
|
68
|
-
}
|
|
69
|
-
_refs.delete(obj);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
private removeAssertModule(context: SequenceExecutorParameters) {
|
|
75
|
-
Object.keys(context).forEach(key => {
|
|
76
|
-
if (context[key]?.assert?.name === 'strict') {
|
|
77
|
-
context[key] = {};
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
type OuterStaticContext = {
|
|
83
|
-
staticContext: StaticContext;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
type StaticContext = {
|
|
87
|
-
$: SequenceExecutorParameters;
|
|
88
|
-
__: ParameterFunctionOperations;
|
|
89
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export interface VirtualMachine {
|
|
2
|
-
engine: Engine;
|
|
3
|
-
create(options: VirtualMachineOptions): Engine;
|
|
4
|
-
run(code: string): object;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface VirtualMachineOptions {
|
|
8
|
-
globalObject?: object;
|
|
9
|
-
staticObject?: object;
|
|
10
|
-
timeout?: number;
|
|
11
|
-
memoryLimit?: number;
|
|
12
|
-
async?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type Engine = any;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { VM } from 'vm2';
|
|
2
|
-
import { SequenceExecutorParameters } from '../../../../core/dist/parameters';
|
|
3
|
-
|
|
4
|
-
import { Engine, VirtualMachine, VirtualMachineOptions } from './virtual-machine';
|
|
5
|
-
|
|
6
|
-
export class VM2VirtualMachine implements VirtualMachine {
|
|
7
|
-
public engine: VM;
|
|
8
|
-
private DEFAULT_TIMOUT_MS = Number(process.env.POSTSCRIPT_TIMEOUT_MS) || 1000;
|
|
9
|
-
|
|
10
|
-
create(options: VirtualMachineOptions): Engine {
|
|
11
|
-
const { timeout, globalObject, async, staticObject } = options;
|
|
12
|
-
this.engine = new VM({
|
|
13
|
-
timeout: timeout || this.DEFAULT_TIMOUT_MS,
|
|
14
|
-
fixAsync: !async,
|
|
15
|
-
eval: false,
|
|
16
|
-
wasm: false,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
this.makeStatic(staticObject);
|
|
20
|
-
|
|
21
|
-
this.setGlobals(globalObject);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
makeStatic(obj: object = {}) {
|
|
25
|
-
this.deepFreeze(obj);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
deepFreeze = (obj: object) => {
|
|
29
|
-
for (const key of Object.keys(obj)) {
|
|
30
|
-
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
31
|
-
this.engine.freeze(obj[key], key); // freeze me
|
|
32
|
-
this.deepFreeze(obj[key]); // freeze my childrens
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return this.engine.freeze(obj); // freeze root
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
setGlobals = (globalObject: SequenceExecutorParameters = {}) => {
|
|
39
|
-
this.engine.setGlobals(globalObject);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
run(code: string): SequenceExecutorParameters {
|
|
43
|
-
return this.engine.run(code);
|
|
44
|
-
}
|
|
45
|
-
}
|
package/src/report-types.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Failures } from './failures';
|
|
2
|
-
import { MillInfo } from './mill-info';
|
|
3
|
-
import { PerRequestResTime, PerRequestStats } from './request-stats';
|
|
4
|
-
|
|
5
|
-
export type LoadResult = 'done' | 'aborted' | 'failed';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* This report contains all the info that comes from Redis each time there is a status update.
|
|
9
|
-
*/
|
|
10
|
-
export interface LoadStatusReport extends AggregatedStatsReport {
|
|
11
|
-
endTime?: number;
|
|
12
|
-
startTime?: number;
|
|
13
|
-
result?: LoadResult;
|
|
14
|
-
activeSessions?: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* This report contains all the aggregated stats computed from individual mill reports.
|
|
19
|
-
*/
|
|
20
|
-
export interface AggregatedStatsReport extends BasicStatsReport {
|
|
21
|
-
/**
|
|
22
|
-
* The number of separate sessions / mills that sent at least one report.
|
|
23
|
-
*/
|
|
24
|
-
reportedSessions?: number;
|
|
25
|
-
|
|
26
|
-
append?: boolean;
|
|
27
|
-
failures?: Failures;
|
|
28
|
-
browserStatsMap?: StatsMap;
|
|
29
|
-
locationStatsMap?: StatsMap;
|
|
30
|
-
serverMetrics?: ServerMetrics;
|
|
31
|
-
avgResTimeSequence?: SequenceObj;
|
|
32
|
-
requestStats?: PerRequestResTime;
|
|
33
|
-
failureReportsMap?: HashKeysToReportIds;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* A mapping that aggregates stats according to a certain feature, e.g. stats per browser version.
|
|
38
|
-
*/
|
|
39
|
-
export interface StatsMap {
|
|
40
|
-
[feature: string]: BasicStatsReport & {
|
|
41
|
-
sessions: number;
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* A sequence of stats (currently only the average response time) reported within a certain
|
|
47
|
-
* interval (between `firstTime` and `lastTime`).
|
|
48
|
-
*/
|
|
49
|
-
export interface SequenceObj {
|
|
50
|
-
append?: boolean;
|
|
51
|
-
sequence: ClientMetrics;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export type ClientMetrics = ClientMetricsClump[];
|
|
55
|
-
|
|
56
|
-
export type ClientMetricsClump = {
|
|
57
|
-
s?: number;
|
|
58
|
-
f?: number;
|
|
59
|
-
avg: number;
|
|
60
|
-
time: number;
|
|
61
|
-
p50?: number;
|
|
62
|
-
p95?: number;
|
|
63
|
-
weight: number;
|
|
64
|
-
concurrency: number;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export type ServerMetrics = ServerMetricsClump[];
|
|
68
|
-
|
|
69
|
-
export type ServerMetricsClump = {
|
|
70
|
-
_t: number;
|
|
71
|
-
|
|
72
|
-
uc?: number;
|
|
73
|
-
tc?: number;
|
|
74
|
-
|
|
75
|
-
tm?: number;
|
|
76
|
-
hm?: number;
|
|
77
|
-
uhm?: number;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export type HashKeysToReportIds = { [hashKey: string]: string };
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* This is the report sent to Redis every time a mill report is received.
|
|
84
|
-
*/
|
|
85
|
-
export type ToStoreStatsReport = StatsReportWithMillInfo & {
|
|
86
|
-
timestamp: number;
|
|
87
|
-
firstReport: boolean;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* This report includes a single mill stats report along with additional meta data.
|
|
92
|
-
*/
|
|
93
|
-
export type StatsReportWithMillInfo = FromMillStatsReport &
|
|
94
|
-
MillInfo & {
|
|
95
|
-
lordId: string;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* The stats report sent by the mill.
|
|
100
|
-
*/
|
|
101
|
-
export interface FromMillStatsReport extends BasicStatsReport {
|
|
102
|
-
failures?: Failures;
|
|
103
|
-
requestStats?: PerRequestStats;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* The basic stats we are usually interested in.
|
|
108
|
-
*/
|
|
109
|
-
export interface BasicStatsReport {
|
|
110
|
-
hits?: number;
|
|
111
|
-
avgResTime?: number;
|
|
112
|
-
failedIterations?: number;
|
|
113
|
-
successfulIterations?: number;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function isInformative({
|
|
117
|
-
hits,
|
|
118
|
-
avgResTime,
|
|
119
|
-
failedIterations,
|
|
120
|
-
successfulIterations,
|
|
121
|
-
}: FromMillStatsReport) {
|
|
122
|
-
return (
|
|
123
|
-
(hits && hits > 0 && avgResTime != null && avgResTime >= 0) ||
|
|
124
|
-
(failedIterations && failedIterations > 0) ||
|
|
125
|
-
(successfulIterations && successfulIterations > 0)
|
|
126
|
-
);
|
|
127
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Failures } from './failures';
|
|
2
|
-
import { PerRequestStats } from './request-stats';
|
|
3
|
-
import { Parameters } from '@loadmill/core/dist/parameters';
|
|
4
|
-
import {
|
|
5
|
-
LoadmillHeaders,
|
|
6
|
-
LoadmillRequest,
|
|
7
|
-
PostFormData,
|
|
8
|
-
RequestPostData,
|
|
9
|
-
} from '@loadmill/core/dist/request';
|
|
10
|
-
|
|
11
|
-
export function extendSequenceResult(
|
|
12
|
-
result: RequestSequenceResult,
|
|
13
|
-
requests: LoadmillRequest[]
|
|
14
|
-
): ExtendedSequenceResult {
|
|
15
|
-
return {
|
|
16
|
-
...result,
|
|
17
|
-
resolvedRequests: requests.map((request, index: number) => ({
|
|
18
|
-
...request,
|
|
19
|
-
...result.resolvedRequests[index],
|
|
20
|
-
})),
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ExtendedSequenceResult extends RequestSequenceResult {
|
|
25
|
-
resolvedRequests: ExtendedRequest[];
|
|
26
|
-
err?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface RequestSequenceResult {
|
|
30
|
-
failures: Failures;
|
|
31
|
-
avgResTime: number;
|
|
32
|
-
successfulHits: number;
|
|
33
|
-
lastStartedIndex: number;
|
|
34
|
-
requestStats: PerRequestStats;
|
|
35
|
-
resolvedRequests: ResolvedRequest[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type ExtendedRequest = LoadmillRequest & ResolvedRequest;
|
|
39
|
-
|
|
40
|
-
export interface ResolvedRequest {
|
|
41
|
-
url?: string;
|
|
42
|
-
headers?: LoadmillHeaders[];
|
|
43
|
-
postData?: RequestPostData;
|
|
44
|
-
postFormData?: PostFormData;
|
|
45
|
-
|
|
46
|
-
response?: {
|
|
47
|
-
type: string;
|
|
48
|
-
text: string;
|
|
49
|
-
status: number;
|
|
50
|
-
statusText: string;
|
|
51
|
-
headers: LoadmillHeaders[];
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
postParameters?: Parameters[];
|
|
55
|
-
|
|
56
|
-
unexpectedError?: {
|
|
57
|
-
stack: string;
|
|
58
|
-
message: string;
|
|
59
|
-
properties: string;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
retried?: number;
|
|
63
|
-
}
|
package/src/request-stats.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface PerRequestStats {
|
|
2
|
-
[index: number]: RequestStats;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export interface RequestStats {
|
|
6
|
-
resTimes: number[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface PerRequestResTime {
|
|
10
|
-
[index: number]: { weight: number; avg: number };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function setReqStats(
|
|
14
|
-
reqStats: PerRequestStats,
|
|
15
|
-
index,
|
|
16
|
-
...resTimes: number[]
|
|
17
|
-
) {
|
|
18
|
-
const stats = reqStats[index] || (reqStats[index] = { resTimes: [] });
|
|
19
|
-
stats.resTimes.push(...resTimes);
|
|
20
|
-
}
|
package/src/res-keeper.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { ObjectMap } from '@loadmill/universal/dist/object-map';
|
|
2
|
-
import * as promiseUtils from '@loadmill/universal/dist/promise-utils';
|
|
3
|
-
import { getFailureKeys } from './failures';
|
|
4
|
-
import { RequestSequenceResult } from './request-sequence-result';
|
|
5
|
-
|
|
6
|
-
export class ResKeeper {
|
|
7
|
-
knownKeysToResults: { [key: string]: string } = {};
|
|
8
|
-
results = new ObjectMap<RequestSequenceResult>(this.generateResultKey);
|
|
9
|
-
|
|
10
|
-
constructor(private generateResultKey?) {}
|
|
11
|
-
|
|
12
|
-
getKnownKeys = () => Object.keys(this.knownKeysToResults);
|
|
13
|
-
|
|
14
|
-
mapToResultIds = (failureKeys) => {
|
|
15
|
-
const map: { [key: string]: string } = {};
|
|
16
|
-
failureKeys.forEach((key) => (map[key] = this.knownKeysToResults[key]));
|
|
17
|
-
|
|
18
|
-
return map;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
keepIfNeeded = (result: RequestSequenceResult, keepFor?: number) => {
|
|
22
|
-
const failureKeys = getFailureKeys(result.failures);
|
|
23
|
-
|
|
24
|
-
if (failureKeys.find((key) => !this.knownKeysToResults[key])) {
|
|
25
|
-
// We keep it:
|
|
26
|
-
const id = this.results.add(result);
|
|
27
|
-
failureKeys.forEach((key) => (this.knownKeysToResults[key] = id));
|
|
28
|
-
|
|
29
|
-
if (keepFor) {
|
|
30
|
-
promiseUtils.delay(keepFor).then(() => this.results.remove(id));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
popForKeys = (failureKeys: string[], withIds = false) => {
|
|
36
|
-
return failureKeys
|
|
37
|
-
.map((key) => {
|
|
38
|
-
const id = this.knownKeysToResults[key];
|
|
39
|
-
|
|
40
|
-
if (id) {
|
|
41
|
-
const res = this.results.get(id);
|
|
42
|
-
this.results.remove(id);
|
|
43
|
-
|
|
44
|
-
if (withIds && res) {
|
|
45
|
-
res['id'] = id;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return res;
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
.filter(Boolean);
|
|
52
|
-
};
|
|
53
|
-
}
|
package/src/sampler.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import log from '@loadmill/universal/dist/log';
|
|
2
|
-
import * as mathUtils from '@loadmill/universal/dist/math-utils';
|
|
3
|
-
import * as promiseUtils from '@loadmill/universal/dist/promise-utils';
|
|
4
|
-
import { minimalRemainingDuration, reportDelay } from '@loadmill/core/dist/conf';
|
|
5
|
-
import { runSingleIteration } from './single-runner';
|
|
6
|
-
import { Failures, mergeFailures } from './failures';
|
|
7
|
-
import { PerRequestStats, setReqStats } from './request-stats';
|
|
8
|
-
import { Work } from './work';
|
|
9
|
-
import { messageCreators } from './message-creators';
|
|
10
|
-
import { DEFAULT_DURATION, DEFAULT_ITERATION_DELAY } from '@loadmill/core/dist/conf/defaults';
|
|
11
|
-
|
|
12
|
-
// 5 minutes:
|
|
13
|
-
const RES_KEEP_TIME = 5 * 60 * 1000;
|
|
14
|
-
|
|
15
|
-
export interface SamplerFaja {
|
|
16
|
-
cancelWork(finished: boolean);
|
|
17
|
-
send(obj: string);
|
|
18
|
-
reportIntervalId;
|
|
19
|
-
isStopped: boolean;
|
|
20
|
-
keeper;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class Sampler {
|
|
24
|
-
avgResTime = 0;
|
|
25
|
-
expired = false;
|
|
26
|
-
successfulHits = 0;
|
|
27
|
-
failedIterations = 0;
|
|
28
|
-
startedIterations = 0;
|
|
29
|
-
failures: Failures = {};
|
|
30
|
-
successfulIterations = 0;
|
|
31
|
-
requestStats: PerRequestStats = {};
|
|
32
|
-
|
|
33
|
-
constructor(private samplerMill: SamplerFaja, private work: Work) {}
|
|
34
|
-
|
|
35
|
-
startSampling = () => {
|
|
36
|
-
this.samplerMill.cancelWork(false);
|
|
37
|
-
|
|
38
|
-
promiseUtils.delay(this.work.duration || DEFAULT_DURATION).then(
|
|
39
|
-
() => {
|
|
40
|
-
if (!this.samplerMill.isStopped) {
|
|
41
|
-
log.debug('Time\'s up!');
|
|
42
|
-
this.expired = true;
|
|
43
|
-
this.sendReport();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const requests = this.work.requests;
|
|
49
|
-
const iterationDelay = this.work.iterationDelay || DEFAULT_ITERATION_DELAY;
|
|
50
|
-
|
|
51
|
-
const reportDelayy = reportDelay(iterationDelay, requests);
|
|
52
|
-
this.samplerMill.reportIntervalId = setInterval(
|
|
53
|
-
this.sendReport,
|
|
54
|
-
reportDelayy
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
this.samplerMill.isStopped = false;
|
|
58
|
-
this.runAll();
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
runAll = async () => {
|
|
62
|
-
while (!this.isDone()) {
|
|
63
|
-
++this.startedIterations;
|
|
64
|
-
log.trace('Executing iteration: ', this.startedIterations);
|
|
65
|
-
|
|
66
|
-
const res = await runSingleIteration(this.work);
|
|
67
|
-
this.samplerMill.keeper.keepIfNeeded(res, RES_KEEP_TIME);
|
|
68
|
-
|
|
69
|
-
const resFailures = res.failures;
|
|
70
|
-
|
|
71
|
-
if (!resFailures || Object.keys(resFailures).length === 0) {
|
|
72
|
-
++this.successfulIterations;
|
|
73
|
-
} else {
|
|
74
|
-
++this.failedIterations;
|
|
75
|
-
mergeFailures(this.failures, resFailures);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.avgResTime = mathUtils.calcAvg(
|
|
79
|
-
this.avgResTime,
|
|
80
|
-
this.successfulHits,
|
|
81
|
-
res.avgResTime,
|
|
82
|
-
res.successfulHits
|
|
83
|
-
);
|
|
84
|
-
this.successfulHits += res.successfulHits;
|
|
85
|
-
|
|
86
|
-
Object.keys(res.requestStats).forEach(index => {
|
|
87
|
-
setReqStats(this.requestStats, index, ...res.requestStats[index].resTimes);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (!this.isDone()) {
|
|
92
|
-
// We count only the delay of the requests that were NOT ATTEMPTED.
|
|
93
|
-
// Note that the first request delay is always ignored:
|
|
94
|
-
const skipCount = res.lastStartedIndex + 1;
|
|
95
|
-
await promiseUtils.delay(
|
|
96
|
-
minimalRemainingDuration(
|
|
97
|
-
this.work.iterationDelay || DEFAULT_ITERATION_DELAY,
|
|
98
|
-
this.work.requests,
|
|
99
|
-
skipCount
|
|
100
|
-
)
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (!this.samplerMill.isStopped) {
|
|
106
|
-
log.debug('Finished last iteration:', this.startedIterations);
|
|
107
|
-
this.sendReport();
|
|
108
|
-
this.samplerMill.cancelWork(true);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
isDone = () => {
|
|
113
|
-
return this.samplerMill.isStopped || this.expired || this.startedIterations >= this.work.iterations;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
sendReport = () => {
|
|
117
|
-
const report = {
|
|
118
|
-
failures: this.failures,
|
|
119
|
-
hits: this.successfulHits,
|
|
120
|
-
avgResTime: this.avgResTime,
|
|
121
|
-
requestStats: this.requestStats,
|
|
122
|
-
failedIterations: this.failedIterations,
|
|
123
|
-
successfulIterations: this.successfulIterations,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
log.trace('Sending report:', report);
|
|
127
|
-
this.samplerMill.send(messageCreators.report(report));
|
|
128
|
-
|
|
129
|
-
this.failures = {};
|
|
130
|
-
this.requestStats = {};
|
|
131
|
-
this.successfulIterations = this.successfulHits = this.failedIterations = this.avgResTime = 0;
|
|
132
|
-
};
|
|
133
|
-
}
|