Requests
7 minute read
You can make GET
, POST
, PUT
, PATCH
, DELETE
and HEAD
requests.
Each HTTP verb has a corresponding method defined on session
:
session.get("/path")
or session.post("/users/create")
.
All requests require at least the request path and can have additional options.
Note that targets have to be specified using definition.addTarget()
.
session.get("/users/sign_up", requestOptions);
session.post("/users/create", {
tag: "create-user",
payload: {
name: "Smith",
email: "smith@example.com",
password: "secret"
}
});
Request options You can specify options for each request. Request options are optional and are specified within each request as a hash. Read on for a full list of all available options.
Request URL parameters using Placeholder
Use :placeholder
keywords in the request URL and fill them with the params
key in the request options object:
definition.session("get-url-parameters-session", function(session) {
session.get("/root/:category/:product_id?view=:view", {
params: {
category: "foo",
view: "FULL",
}
});
});
Mind that we replace category
and view
, but not product_id
.
The result is a GET request to /root/foo/:product_id?view=FULL
.
Request Options
Payload for POST/PUT/PATCH/DELETE requests
payload
can either be:
- a string, which is send as plain text
- or an object (key-value pairs), which is encoded and send as
application/x-www-form-urlencoded
.
Note that some applications might require an application/json
Content-Type header for JSON encoded payloads.
{
// as a plain text string
payload: "payload string"
// -OR- as application/x-www-form-urlencoded
payload: {
email: user.get("email"),
password: user.get("password"),
}
// -OR- as a JSON string
payload: JSON.stringify({
productId: article.get("productId"),
amount: 1
})
}
Uploading binary payloads
If you need to upload binary payloads you can use the payload_from_file
option:
var picture = session.ds.getRawFile("picture.png");
session.post("/upload", {
payload_from_file: picture,
// [more options]
});
In this example, the file picture.png
will be loaded from the data sources of your organization.
Make sure to upload it as a Raw File beforehand.
Multipart Payload
If you need to upload multipart payloads you can pass in a MultiPartBuilder
to the multi_part_payload
option.
See the MultiPart Requests page for details and example.
Request Compression
You can request gzip compression for responses.
The gzip
option will set an Accept-Encoding
header to request compressed responses from the server.
The default value is false
.
Note that the target server has to support that functionality to deliver compressed responses.
{
// use gzip compression, default: false
gzip: true
}
HTTP Headers
The headers
option is used to set HTTP request headers (key-value pairs).
Note that you cannot set headers beginning with X-StormForger-
.
Although allowed by RFC 2616 we currently only support unique header names.
{
headers: {
"X-AwesomeApp-Token": user.get("api_token"),
"X-AwesomeApp-Mail": user.get("mail"),
}
}
Tag Requests
The tag
option specifies an identifier (tag) that is associated with the request.
A tag may consist of letters, numbers, underscores and dashes and has to start with a letter.
Tags can be used when analyzing the test run.
{
tag: "logout"
}
NOTE: You can skip requests based on their tag with the exclude_tags
test option.
HTTP Basic Authentication
You can use HTTP basic access authentication.
The authentication
option is providing an HTTP Basic Authentication.
{
authentication: {
username: "tisba",
password: "letmein",
}
}
Response Extraction
The extraction
option is a way to tell the test to extract parts of the response body, headers or cookies (see extraction).
{
// use response content extraction
extraction: {
jsonpath: {
"accessToken": "authorization.token",
}
}
}
Cookies
Each client automatically manages a cookie jar.
Cookies sent by the server in responses to requests (via Set-Cookie
header) are automatically added, updated and removed.
You can add a cookie to a request using the additional_cookies
option.
Note that this cookies will only be set for the specific request.
{
additional_cookies: [
{
name: "csrfToken",
value: session.getVar("token"),
},
]
}
XHR-Shorthand
Set the xhr
option to true
to perform a request with the correct headers for an XHR-Request.
session.get(url, {
xhr: true
});
This will add the X-Requested-With: XMLHttpRequest
header to the current request.
CORS-Shorthand
When performing a request that require a CORS preflight request you can set the following option that will create a preceding OPTIONS
-Request that includes the correct Access-Control-Request-Method
, Access-Control-Request-Headers
and Origin
-Headers.
session.get("/api/login", {
cors: { origin: "https://www.example.com", tag: "cors-request-tag" }
});
origin
is required and has to be a valid Origin-Header according to RFC 6454.tag
is optional and will default to either the requeststag
-value (if provided, see Tag Requests) or the literal"cors"
Abort on Error
The abort_on_error
option allows to abort the session if any http status code in the 400 to 500 range is received.
This is an alternative to assertions and can also be set as a session default.
Setting Defaults
You can set defaults which will apply to requests like this:
session.defaults.setGzip(true);
session.defaults.setAuthentication({ username: "user", password: "letmein" });
session.defaults.setHeader("Host", "www.example.com");
session.defaults.sendRequestId(false); // to deactivate the request-id
session.defaults.sendRequestId({"header": "Correlation-ID"}); // change the request-id header
session.defaults.setAbortOnError(true);
Note that the following rules apply:
- defaults apply only for requests following the definition of defaults
- defaults are passed into sub-contexts (e.g. in case of
if
,times
, etc) - defaults can be unset (using
session.defaults.unset()
). This only unsets defaults for the current context! Defaults will apply again if the sub-context has ended - defaults defined in sub-contexts do not apply after the sub-context has ended
Request Tracing
All requests are sent with certain headers to help tracing and understanding requests flowing through your infrastructure.
Header | Example Value | Comment |
---|---|---|
User-Agent |
StormForger-X/%VERSION (+https://stormforger.com) |
The user agent. The version will change over time. |
X-Request-ID |
sf-{test_run_uid}-{request_id} |
A unique ID for every request - The test run UID makes it easy to correlate which test run originated the request |
X-StormForger-User |
154123c:1512415123415123acdf |
The user that started the test run. Note that is an internal format and users should not rely on a specific value |
The X-Request-ID
header can be deactivated by setting the request_id
option to false
.
You can also change the header to a different name as follows:
session.get("/", {
"request_id": {
"header": "Correlation-ID"
}
});
Note that this can also be configured in the setting defaults. If you want to provide your own request-ids, just set them via headers - We will not add a request-id if there is a conflict.
Connection Keep-Alive
Connection keep-alive only works within a single session. If the test case starts many sessions all doing only one request, no connections will be reused and you also test the number of connections per second.
If you want to actively close a connection after a request, you can simply set the header: Connection: close
.
Timeouts
Each client launched with an arrival phase has its own HTTP client with individual timeouts. You can see these timeouts below.
Name | Value | Comment |
---|---|---|
KeepAliveInterval | 30s | KeepAlive is the interval between keep-alive probes to check if the connection is still alive |
IdleConnTimeout | 90s | How long connections are kept open if unused |
ConnectTimeout | 30s | TCP connect timeout |
TLSHandshakeTimeout | 10s | Timeout for the TLS handshake |
RequestTimeout | 120s | Overall request timeout - Includes connection, sending the request and receiving the response |
session.lastHttpStatus()
The session.lastHttpStatus()
helper returns the status code of the last request performed by the current session.
If no status code is available, 999
is returned.
session.post(...);
session.check("checkout", session.lastHttpStatus(), "=", 200);
session.get("/products/:product", {params: {product: randomProductId}});
session.check("product_access_denied", session.lastHttpStatus(), ">=", 400);
NOTE: the lastHttpStatus()
function returns the status of the previous request.
If you want to keep the status around for longer, you have to save it to variable via setVar()
.
session.redirectTarget()
session.redirectTarget()
returns an URL based the location
header of the last request/response performed on the current session.
Note that the status code must be a redirect status (3xx, except 304).
This function guarantees that the returned URL has a protocol and host by backfilling the missing data from the previous request, if needed.
session.post("http://example.com/login", { abort_on_error: true });
session.assert("redirect_received", session.redirectTarget(), "!=", "");
session.get(session.redirectTarget());
In the example above, we perform a request to /login
, aborting the session if we don’t receive a status code in the 2xx or 3xx range.
Next, we check if we received a redirect target and follow it.
Assuming we receive a 307 (temporary redirect) status code and /welcome
in the location
header, the second request would go against http://example.com/welcome
, since session.redirectTarget()
returns an URL backfilled with a host and protocol.
Please note: If you use session.redirectTarget()
to follow a redirect, you need to make sure that the target is allowed. Otherwise you will see “URL forbidden” errors in your test run.