Skip to content

Commit

Permalink
feat: add setupRequest per request for requests array (#239)
Browse files Browse the repository at this point in the history
* feat: add setupRequest per request for requests array

* fix: removed tracking of package-lock.json
  • Loading branch information
alex-ppg authored and mcollina committed Jan 25, 2020
1 parent 7c55bd7 commit 7a8c4f9
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -26,6 +26,9 @@ build/Release
# Dependency directory
node_modules

# Dependency lock
package-lock.json

# Optional npm cache directory
.npm

Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -233,7 +233,7 @@ Start autocannon against the given target.
* `connectionRate`: A `Number` stating the rate of requests to make per second from each individual connection. No rate limiting by default. _OPTIONAL_
* `overallRate`: A `Number` stating the rate of requests to make per second from all connections. `connectionRate` takes precedence if both are set. No rate limiting by default. _OPTIONAL_
* `reconnectRate`: A `Number` which makes the individual connections disconnect and reconnect to the server whenever it has sent that number of requests. _OPTIONAL_
* `requests`: An `Array` of `Object`s which represents the sequence of requests to make while benchmarking. Can be used in conjunction with the `body`, `headers` and `method` params above. The `Object`s in this array can have `body`, `headers`, `method`, or `path` attributes, which overwrite those that are passed in this `opts` object. Therefore, the ones in this (`opts`) object take precedence and should be viewed as defaults. Check the samples folder for an example of how this might be used. _OPTIONAL_.
* `requests`: An `Array` of `Object`s which represents the sequence of requests to make while benchmarking. Can be used in conjunction with the `body`, `headers` and `method` params above. The `Object`s in this array can have `body`, `headers`, `method`, or `path` attributes, which overwrite those that are passed in this `opts` object. Therefore, the ones in this (`opts`) object take precedence and should be viewed as defaults. Additionally, an optional `setupRequest` `Function` may be provided that will mutate the raw `request` object, e.g. `request.method = 'GET'`. Check the samples folder for an example of how this might be used. _OPTIONAL_.
* `idReplacement`: A `Boolean` which enables the replacement of `[<id>]` tags within the request body with a randomly generated ID, allowing for unique fields to be sent with requests. Check out [an example of programmatic usage](./samples/using-id-replacement.js) can be found in the samples. _OPTIONAL_ default: `false`
* `forever`: A `Boolean` which allows you to setup an instance of autocannon that restarts indefinitely after emiting results with the `done` event. Useful for efficiently restarting your instance. To stop running forever, you must cause a `SIGINT` or call the `.stop()` function on your instance. _OPTIONAL_ default: `false`
* `servername`: A `String` identifying the server name for the SNI (Server Name Indication) TLS extension. _OPTIONAL_ default: `undefined`.
Expand Down
4 changes: 4 additions & 0 deletions lib/httpRequestBuilder.js
Expand Up @@ -13,6 +13,7 @@ function requestBuilder (defaults) {
headers: {},
body: Buffer.alloc(0),
hostname: 'localhost',
setupRequest: reqData => reqData,
port: 80
}

Expand All @@ -27,6 +28,9 @@ function requestBuilder (defaults) {
reqData.headers = Object.assign({}, defaults.headers, reqData.headers)

reqData = Object.assign({}, defaults, reqData)

reqData = reqData.setupRequest(reqData)

// for some reason some tests fail with method === undefined
// the reqData.method should be set to SOMETHING in this case
// cannot find reason for failure if `|| 'GET'` is taken out
Expand Down
8 changes: 6 additions & 2 deletions samples/requests-sample.js
Expand Up @@ -37,15 +37,19 @@ function startBench () {
// this will automatically add the pregenerated auth token
},
{
method: 'PUT', // this should be a put for modifying secret details
method: 'GET', // this should be a put for modifying secret details
path: '/mySecretDetails',
headers: { // let submit some json?
'Content-type': 'application/json; charset=utf-8'
},
// we need to stringify the json first
body: JSON.stringify({
name: 'my new name'
})
}),
setupRequest: reqData => {
reqData.method = 'PUT' // we are overriding the method 'GET' to 'PUT' here
return reqData
}
}
]
}, finishedBench)
Expand Down
48 changes: 48 additions & 0 deletions test/requestIterator.test.js
Expand Up @@ -187,3 +187,51 @@ test('request iterator should replace all [<id>] tags with generated IDs when ca
t.equal(result.includes('[<id>]'), false, 'One or more [<id>] tags were not replaced')
t.equal(result.slice(-1), '0', 'Generated ID should end with request number')
})

test('request iterator should properly mutate requests if a setupRequest function is located', (t) => {
t.plan(6)

const opts = server.address()
opts.method = 'POST'

let i = 0

const requests1 = [
{
body: 'hello world',
setupRequest: req => {
req.body += i++
return req
}
},
{
method: 'POST',
body: 'modified',
setupRequest: req => {
req.method = 'GET'
return req
}
}
]

const request1Res = Buffer.from(`POST / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: keep-alive\r\nContent-Length: 12\r\n\r\nhello world0`)
const request2Res = Buffer.from(`POST / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: keep-alive\r\nContent-Length: 9\r\n\r\nmodified1`)
const request3Res = Buffer.from(`GET / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: keep-alive\r\nContent-Length: 8\r\n\r\nmodified`)
const request4Res = Buffer.from(`POST / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: keep-alive\r\nheader: modifiedHeader\r\nContent-Length: 9\r\n\r\nmodified2`)
const request5Res = Buffer.from(`POST / HTTP/1.1\r\nHost: localhost:${server.address().port}\r\nConnection: keep-alive\r\n\r\n`)

opts.requests = requests1

const iterator = new RequestIterator(opts)
t.same(iterator.currentRequest.requestBuffer, request1Res, 'request was okay')
iterator.setBody('modified')
t.same(iterator.currentRequest.requestBuffer, request2Res, 'request was okay')
iterator.nextRequest() // verify it didn't affect the other request
t.same(iterator.currentRequest.requestBuffer, request3Res, 'request was okay')
iterator.nextRequest()
t.same(iterator.currentRequest.requestBuffer, request2Res, 'request was okay')
iterator.setHeaders({ header: 'modifiedHeader' })
t.same(iterator.currentRequest.requestBuffer, request4Res, 'request was okay')
iterator.setRequest() // this should build default request
t.same(iterator.currentRequest.requestBuffer, request5Res, 'request was okay')
})

0 comments on commit 7a8c4f9

Please sign in to comment.