/
validate.js
165 lines (133 loc) · 5.27 KB
/
validate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
'use strict'
const defaultOptions = require('./defaultOptions')
const timestring = require('timestring')
const { checkURL } = require('./url')
const multipart = require('./multipart')
const { parseHAR } = require('./parseHAR')
const { hasWorkerSupport } = require('./util')
const isValidFn = (opt) => (!opt || typeof opt === 'function' || typeof opt === 'string')
const lessThanOneError = (label) => new Error(`${label} can not be less than 1`)
const greaterThanZeroError = (label) => new Error(`${label} must be greater than 0`)
const minIfPresent = (val, min) => val !== null && val < min
function safeRequire (path) {
if (typeof path === 'string') {
try {
return require(path)
} catch (err) {}
}
return path
}
function defaultOpts (opts) {
const setupClient = opts.workers ? opts.setupClient : safeRequire(opts.setupClient)
const verifyBody = opts.workers ? opts.verifyBody : safeRequire(opts.verifyBody)
const requests = opts.requests
? opts.requests.map((r) => {
const setupRequest = opts.workers ? r.setupRequest : safeRequire(r.setupRequest)
const onResponse = opts.workers ? r.onResponse : safeRequire(r.onResponse)
return {
...r,
...(setupRequest ? { setupRequest } : undefined),
...(onResponse ? { onResponse } : undefined)
}
})
: undefined
return {
...defaultOptions,
...opts,
...(setupClient ? { setupClient } : undefined),
...(verifyBody ? { verifyBody } : undefined),
...(requests ? { requests } : undefined)
}
}
module.exports = function validateOpts (opts, cbPassedIn) {
if (opts.workers && !hasWorkerSupport) return new Error('Please use node >= 11.7.0 for workers support')
// these need to be validated before defaulting
if (minIfPresent(opts.bailout, 1)) return lessThanOneError('bailout threshold')
if (minIfPresent(opts.connectionRate, 1)) return lessThanOneError('connectionRate')
if (minIfPresent(opts.overallRate, 1)) return lessThanOneError('bailout overallRate')
if (minIfPresent(opts.amount, 1)) return lessThanOneError('amount')
if (minIfPresent(opts.maxConnectionRequests, 1)) return lessThanOneError('maxConnectionRequests')
if (minIfPresent(opts.maxOverallRequests, 1)) return lessThanOneError('maxOverallRequests')
if (opts.form) {
opts.method = opts.method || 'POST'
}
// fill in defaults after
opts = defaultOpts(opts)
if (opts.json === true) {
opts.renderProgressBar = opts.renderResultsTable = opts.renderLatencyTable = false
}
if (opts.requests) {
if (opts.requests.some(r => !isValidFn(r.setupRequest))) {
return new Error('Invalid option setupRequest, please provide a function (or file path when in workers mode)')
}
if (opts.requests.some(r => !isValidFn(r.onResponse))) {
return new Error('Invalid option onResponse, please provide a function (or file path when in workers mode)')
}
}
if (!isValidFn(opts.setupClient)) {
return new Error('Invalid option setupClient, please provide a function (or file path when in workers mode)')
}
if (!isValidFn(opts.verifyBody)) {
return new Error('Invalid option verifyBody, please provide a function (or file path when in workers mode)')
}
if (!checkURL(opts.url) && !opts.socketPath) {
return new Error('url or socketPath option required')
}
if (typeof opts.duration === 'string') {
if (/[a-zA-Z]/.exec(opts.duration)) {
try {
opts.duration = timestring(opts.duration)
} catch (error) {
return error
}
} else {
opts.duration = Number(opts.duration.trim())
}
}
if (typeof opts.duration !== 'number') {
return new Error('duration entered was in an invalid format')
}
if (opts.duration < 0) {
return new Error('duration can not be less than 0')
}
opts.sampleInt = parseFloat(opts.sampleInt)
if (isNaN(opts.sampleInt)) {
return new Error('sample interval entered was in an invalid format')
}
if (opts.sampleInt < 0) {
return new Error('sample interval can not be less than 0')
}
if (opts.expectBody && opts.requests !== defaultOptions.requests) {
return new Error('expectBody cannot be used in conjunction with requests')
}
if (opts.form) {
try {
// Parse multipart upfront to make sure there's no errors
const data = multipart(opts.form)
opts.form = opts.workers ? opts.form : data // but use parsed data only if not in workers mode
} catch (error) {
return error
}
}
opts.harRequests = new Map()
if (opts.har) {
try {
opts.harRequests = parseHAR(opts.har)
} catch (error) {
return error
}
}
if (opts.connections < 1) return lessThanOneError('connections')
if (opts.pipelining < 1) return lessThanOneError('pipelining factor')
if (opts.timeout < 1) return greaterThanZeroError('timeout')
if (opts.ignoreCoordinatedOmission && !opts.connectionRate && !opts.overallRate) {
return new Error('ignoreCoordinatedOmission makes no sense without connectionRate or overallRate')
}
if (opts.forever && cbPassedIn) {
return new Error('should not use the callback parameter when the `forever` option is set to true. Use the `done` event on this event emitter')
}
if (opts.forever && opts.workers) {
return new Error('Using `forever` option isn\'t currently supported with workers')
}
return opts
}