Testing HTTP - Artillery - Io Docs PDF
Testing HTTP - Artillery - Io Docs PDF
HTTP-specific configuration
TLS/SSL
By default, Artillery will reject SSL certificates that it's unable to validate, e.g. self-signed certificates. You may see
errors such as UNABLE_TO_GET_ISSUER_CERT_LOCALLY , UNABLE_TO_VERIFY_LEAF_SIGNATURE , CERT_UNTRUSTED
or one of the other validation error codes
(https://github.com/nodejs/node/blob/30219bfc572101f48d0bc4b01d04a5e22c1c4b74/src/node_crypto.cc#L2166)
when that happens.
You can disable certificate validation with either of the following two options:
config:
target: "https://myapp.staging:3002"
tls:
rejectUnauthorized: false
scenarios:
- ...
Note: This option can be useful for testing in a development / staging environment, but should never be used when
testing a production system.
Request timeout
If a response takes longer than 120 seconds Artillery will abort the request and report an ETIMEDOUT error.
To increase or decrease the default timeout set config.http.timeout to a number (in seconds).
config:
target: "http://my.app"
http:
# Responses have to be sent within 10 seconds or the request will be aborted
timeout: 10
This can be useful to emulate the conditions when the target would normally be behind a load-balancer and would
have a fixed number of connections established at any given time.
Note: this setting is per virtual user, not for the total number of sockets. To limit the total number of sockets, use the
pool setting.
Flow actions
GET / POST / PUT / PATCH / DELETE requests
An HTTP request object may have the following attributes:
url - the request URL; it will be appended to the target but can be fully qualified also
json - a JSON object to be sent in the request body
body - arbitrary data to be sent in the request body
headers - a JSON object describing header key-value pairs
cookie - a JSON object describing cookie key-value pairs
capture - use this to capture values from the response body of a request and store those in variables
Example:
config:
target: "https://example.com"
phases:
- duration: 10
arrivalRate: 1
scenarios:
- flow:
- get:
url: "/"
- post:
url: "/resource"
json:
hello: "world"
Logging
Debug messages can be logged with the log action:
config:
target: "https://example.com"
phases:
- duration: 10
arrivalRate: 1
scenarios:
- flow:
- log: "New virtual user running"
- get:
url: "/"
- post:
url: "/resource"
json:
hello: "world"
Setting Headers
Arbitrary headers may be sent with:
- get:
url: "/test"
headers:
X-My-Header: "123"
- post:
url: "/test"
json:
foo: bar
gzip: true
Basic Auth
- get:
url: "/protected/resource"
auth:
user: myusername
pass: mypassword
Query Strings
Query strings (https://en.wikipedia.org/wiki/Query_string) can be appended directly to the url or set with qs :
- get:
url: "/products"
qs:
search_keyword: "coffee"
page_size: 25
Redirects
Artillery follows redirects by default. To stop Artillery from following redirects, set followRedirect property on a
request to false .
- get:
url: "/test"
followRedirect: false
Forms
URL-encoded forms ( application/x-www-form-urlencoded )
Use the form attribute to send an URL-encoded form (https://www.w3.org/TR/html401/interact/forms.html#h-
17.13.4.1).
- post:
url: "/upload"
form:
name: "Homer Simpson"
favorite_food: "donuts"
- post:
url: "/upload"
formData:
name: "Homer Simpson"
favorite_food: "donuts"
To attach binary data a custom JS function can be used.
First-class file upload support is also provided by Artillery Pro (/pro/) for teams requiring extensive file
uploading functionality in their tests.
Syntax
To tell Artillery to parse a response, add a capture attribute to any request spec like so:
- get:
url: "/"
capture:
json: "$.id"
as: "id"
The capture element must always have an as attribute which names the value for use in subsequent requests, and
one of:
Optionally, a transform attribute may be specified too, which should be a snippet of JS code (as a string)
transforming the value after it has been extracted from the response:
- get:
url: "/journeys"
capture:
xpath: "(//Journey)[1]/JourneyId/text()"
transform: "this.JourneyId.toUpperCase()"
as: "JourneyId"
Where this refers to the context of the virtual user running the scenario, i.e. an object containing all currently
defined variables, including the one that has just been extracted from the response.
- get:
url: "/journeys"
capture:
- xpath: "(//Journey)[1]/JourneyId/text()"
transform: "this.JourneyId.toUpperCase()"
as: "JourneyId"
- header: "x-my-custom-header"
as: "headerValue"
Examples
In the following example, we POST to /pets to create a new resource, capture part of the response (the id of the
new resource) and store it in the variable id . We then use that value in the subsequent request to load the resource
and to check to see if the resource we get back looks right.
- post:
url: "/pets"
json:
name: "Mali"
species: "dog"
capture:
json: "$.id"
as: "id"
- get:
url: "/pets/{{ id }}"
match:
json: "$.name"
value: "{{ name }}"
In the following example, we grab a matching a element at random and then use the value of its href attribute in
another request:
- get:
url: "/some/page"
capture:
- selector: "a[class^=productLink]"
index: "random"
attr: "href"
as: "productUrl"
- get:
url: "{{ productUrl }"
Cookies
Cookies are remembered and re-used by individual virtual users. Custom cookies can be specified with cookie
attribute in individual requests.
- get:
url: "/pets/"
cookie:
saved: "tapir,sloth"
- post:
url: "/pets"
json:
name: "Mali"
species: "dog"
capture:
json: "$.id"
as: "id"
#
# wait for 5 seconds:
#
- think: 5
- get:
url: "/pets/{{ id }}"
match:
json: "$.name"
value: "{{ name }}"
Conditional Requests
An ifTrue attribute may be used to only execute a request in a flow if a condition is met. ifTrue may take two
forms:
. Set to a name of a scenario variable. If the variable is set, the request will be executed.
. Set to a simple conditional expression, which may refer to any of the scenario variables and use one or more of:
. A numeric operation with + , - , * , / , % (modulo), or ^ (power)
. A comparison with == , < , > , <= , >=
. Boolean operation with or , and , or not
Examples
Make a GET request only if the "keyword" scenario variable is set to a value:
- get:
url: "/search?keyword={{ keyword }}"
ifTrue: "keyword"
Make a GET request only if the pageNumber scenario variable is < 10:
- get:
url: "/pages/{{ pageNumber }}"
ifTrue: "pageNumber < 10"
config:
# ... config here ...
scenarios:
- flow:
- loop:
- get:
url: "/"
count: 100
loop is an array - any number of requests can be specified. Variables, cookie and response parsing will work as
expected.
The current step of the loop is available inside a loop through the $loopCount variable (for example going from 1 too
100 in the example above).
In the following example 3 requests would be made, one for each product ID:
- loop:
- get:
url: "/products/{{ $loopElement }}"
over:
- id123
- id456
- id789
The product IDs could also be defined in the config section and used with a loop :
config:
target: "https://my.app.local"
phases:
- duration: 600
arrivalRate: 10
variables:
productIds:
- ["id1", "id2", "id3"]
- ["id4", "id5", "id6"]
scenarios:
- flow:
- loop:
- get:
url: "/products/{{ $loopElement }}"
over: productIds
- loop:
- think: 5
- get:
url: "/some/endpoint"
capture:
- json: $.status
as: "status"
whileTrue: "myFunction"
JS functions may also be run at any point in a scenario with the function action.
config:
target: "https://my.app.dev"
phases:
-
duration: 300
arrivalRate: 1
processor: "./my-functions.js"
scenarios:
- # ... scenarios definitions here ...
//
// my-functions.js
//
module.exports = {
setJSONBody: setJSONBody,
logHeaders: logHeaders
}
This tells Artillery to run the setJSONBody function before the request is made, and to run the logHeaders function
after the response has been received.
scenarios:
- flow:
# Call setupSomeData
- function: "setupSomeData"
- get:
url: "/some/url?q={{ query }}"
Functions invoked with function action have full access to the virtual user's context:
Function signatures
beforeRequest
A function invoked in a beforeRequest hook should have the following signature:
function myBeforeRequestHandler(requestParams, context, ee, next) {
}
Where:
afterResponse
A function invoked in an afterResponse hook should have the following signature:
Where:
Where:
context is the virtual user's context, context.vars is a dictionary containing all defined variables
ee is an event emitter that can be used to communicate with Artillery
next is the callback which must be called for the scenario to continue; it takes no arguments