Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expectbody/assertions #377

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -28,7 +28,7 @@ node_modules

# Dependency lock
package-lock.json

yarn.lock
# Optional npm cache directory
.npm

Expand Down
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -122,6 +122,12 @@ Available options:
-E/--expectBody EXPECTED
Ensure the body matches this value. If enabled, mismatches count towards bailout.
Enabling this option will slow down the load testing.
-N/--expectDuration EXPECTED
Ensure the response duration less than expectDuration. If bigger, reqOverTimes count towards bailout.
Enabling this option will slow down the load testing.
-P/--expectBodySize EXPECTED
Ensure the response body bytes less than expectBodySize. If bigger, reqOverSizes count towards bailout.
Enabling this option will slow down the load testing.
--renderStatusCodes
Print status codes and their respective statistics.
--debug
Expand Down
2 changes: 2 additions & 0 deletions autocannon.js
Expand Up @@ -62,6 +62,8 @@ const alias = {
socketPath: 'S',
excludeErrorStats: 'x',
expectBody: 'E',
expectDuration: 'N',
expectBodySize: 'P',
workers: 'w',
warmup: 'W',
help: 'h'
Expand Down
4 changes: 4 additions & 0 deletions lib/aggregateResult.js
Expand Up @@ -20,6 +20,8 @@ function aggregateResult (results, opts, histograms) {
acc.errors += r.errors
acc.timeouts += r.timeouts
acc.mismatches += r.mismatches
acc.reqOverTimes += r.reqOverTimes
acc.reqOverSizes += r.reqOverSizes
acc.non2xx += r.non2xx
acc.resets += r.resets
acc['1xx'] += r['1xx']
Expand Down Expand Up @@ -53,6 +55,8 @@ function aggregateResult (results, opts, histograms) {
errors: aggregated.errors,
timeouts: aggregated.timeouts,
mismatches: aggregated.mismatches,
reqOverTimes: aggregated.reqOverTimes,
reqOverSizes: aggregated.reqOverSizes,
non2xx: aggregated.non2xx,
resets: aggregated.resets,
'1xx': aggregated['1xx'],
Expand Down
12 changes: 11 additions & 1 deletion lib/httpClient.js
Expand Up @@ -22,6 +22,8 @@ function Client (opts) {
this.opts.pipelining = this.opts.pipelining || 1
this.opts.port = this.opts.port || 80
this.opts.expectBody = this.opts.expectBody || null
this.opts.expectDuration = this.opts.expectDuration || Infinity
this.opts.expectBodySize = this.opts.expectBodySize || Infinity
this.opts.tlsOptions = this.opts.tlsOptions || {}
this.timeout = (this.opts.timeout || 10) * 1000
this.ipc = !!this.opts.socketPath
Expand Down Expand Up @@ -90,11 +92,19 @@ function Client (opts) {
if (!this.destroyed && this.reconnectRate && this.reqsMade % this.reconnectRate === 0) {
return this._resetConnection()
}

if (!this.destroyed) {
if (this.opts.expectBody && this.opts.expectBody !== resp.body) {
if (this.opts.expectBody && !resp.body.includes(this.opts.expectBody)) {
return this.emit('mismatch', resp.body)
}

if (this.opts.expectDuration && resp.duration > this.opts.expectDuration) {
return this.emit('reqOverTime', resp.duration)
}
if (this.opts.expectBodySize && resp.bytes > this.opts.expectBodySize) {
return this.emit('reqOverSize', resp.bytes)
}

this.requestIterator.recordBody(resp.req, resp.headers.statusCode, resp.body, resp.headers.headers)

this.emit('response', resp.headers.statusCode, resp.bytes, resp.duration, this.rate)
Expand Down
10 changes: 10 additions & 0 deletions lib/run.js
Expand Up @@ -37,6 +37,8 @@ function run (opts, tracker, cb) {
let errors = 0
let timeouts = 0
let mismatches = 0
let reqOverTimes = 0
let reqOverSizes = 0
let totalBytes = 0
let totalRequests = 0
let totalCompletedRequests = 0
Expand Down Expand Up @@ -75,6 +77,8 @@ function run (opts, tracker, cb) {
url.socketPath = opts.socketPath
url.servername = opts.servername
url.expectBody = opts.expectBody
url.expectDuration = opts.expectDuration
url.expectBodySize = opts.expectBodySize

return url
})
Expand Down Expand Up @@ -117,6 +121,8 @@ function run (opts, tracker, cb) {
errors: errors,
timeouts: timeouts,
mismatches: mismatches,
reqOverSizes,
reqOverTimes,
non2xx: statusCodes[0] + statusCodes[2] + statusCodes[3] + statusCodes[4],
statusCodeStats,
resets: resets,
Expand Down Expand Up @@ -148,6 +154,8 @@ function run (opts, tracker, cb) {
errors = 0
timeouts = 0
mismatches = 0
reqOverTimes = 0
reqOverSizes = 0
totalBytes = 0
totalRequests = 0
totalCompletedRequests = 0
Expand Down Expand Up @@ -201,6 +209,8 @@ function run (opts, tracker, cb) {
client.on('response', onResponse)
client.on('connError', onError)
client.on('mismatch', onExpectMismatch)
client.on('reqOverTime', () => { reqOverTimes++ })
client.on('reqOverSize', () => { reqOverSizes++ })
client.on('reset', () => { resets++ })
client.on('timeout', onTimeout)
client.on('request', () => { totalRequests++ })
Expand Down
67 changes: 67 additions & 0 deletions test/run.test.js
Expand Up @@ -61,6 +61,8 @@ test('init', (t) => {

t.equal(result.errors, 0, 'no errors')
t.equal(result.mismatches, 0, 'no mismatches')
t.equal(result.reqOverTimes, 0, 'no reqOverTimes')
t.equal(result.reqOverSizes, 0, 'no reqOverSizes')
t.equal(result.resets, 0, 'no resets')

t.equal(result['1xx'], 0, '1xx codes')
Expand Down Expand Up @@ -126,6 +128,8 @@ test('tracker.stop()', (t) => {

t.equal(result.errors, 0, 'no errors')
t.equal(result.mismatches, 0, 'no mismatches')
t.equal(result.reqOverTimes, 0, 'no reqOverTimes')
t.equal(result.reqOverSizes, 0, 'no reqOverSizes')

t.equal(result['1xx'], 0, '1xx codes')
t.equal(result['2xx'], result.requests.total, '2xx codes')
Expand Down Expand Up @@ -327,6 +331,69 @@ test('run should produce 0 mismatches with expectBody set and matches', (t) => {
})
})

test('run should produce count of reqOverTimes with expectDuration set', (t) => {
t.plan(2)

const server = helper.startServer({ delayResponse: 10 })

initJob({
url: 'http://localhost:' + server.address().port,
expectDuration: 1,
maxOverallRequests: 10,
timeout: 100
}, function (err, result) {
t.error(err)
t.equal(result.reqOverTimes, 10)
t.end()
})
})

test('run should produce 0 reqOverTimes with expectDuration set and matches', (t) => {
t.plan(2)

initJob({
url: 'http://localhost:' + server.address().port,
expectDuration: 1000,
maxOverallRequests: 10
}, function (err, result) {
t.error(err)
t.equal(result.reqOverTimes, 0)
t.end()
})
})

test('run should produce count of reqOverSizes with expectBodySize set', (t) => {
t.plan(2)

const responseBody = 'hello dave hello dave hello dave hello dave hello dave hello dave hello dave hello dave hello dave'
const server = helper.startServer({ body: responseBody })

initJob({
url: 'http://localhost:' + server.address().port,
expectBodySize: 10,
maxOverallRequests: 10,
timeout: 100
}, function (err, result) {
t.error(err)
t.equal(result.reqOverSizes, 10)
t.end()
})
})

test('run should produce 0 reqOverSizes with expectBodySize set and matches', (t) => {
t.plan(2)

initJob({
url: 'http://localhost:' + server.address().port,
expectBodySize: 1000,
maxOverallRequests: 10
}, function (err, result) {
t.error(err)
t.equal(result.reqOverSizes, 0)
t.end()
})
})

test('run should accept a unix socket/windows pipe', (t) => {
t.plan(11)

Expand Down
2 changes: 2 additions & 0 deletions test/workers.test.js
Expand Up @@ -80,6 +80,8 @@ test('init with workers', { skip: !hasWorkerSupport }, (t) => {

t.equal(result.errors, 0, 'no errors')
t.equal(result.mismatches, 0, 'no mismatches')
t.equal(result.reqOverTimes, 0, 'no reqOverTimes')
t.equal(result.reqOverSizes, 0, 'no reqOverSizes')
t.equal(result.resets, 0, 'no resets')

t.equal(result['1xx'], 0, '1xx codes')
Expand Down