HTTP DSL
Architecture
The HTTP DSL lets you use a specialised HTTP proxy (driver) to communicate with target servers, so that tests can be executed anywhere while the driver has access to the target resources.
The DSL provides handy methods to construct the final HTTP request as well as parse the output. There are specialised methods for REST calls with JSON parsing and specialised methods for SOAP calls with XML parsing. A separate set of methods supports authorization, including complex authentication flows.
Example:
class TestClass {
@Test
public void sampleTest(
@Capability(key = "browserName", value = "pn5-driver8")
HttpApplication client) {
client
.prepareRestRequest("https://example.com/api/animals", "GET")
.withBasicAuth("user", "password")
.withQueryParam("id", "1")
.sendAndGetResponse()
.assertStatus(200)
.assertPayloadContains("cat");
}
}
In the background, Pumpo#5 starts a session on the testing farm by instantiating an image of Driver8-Universal which then plays the role of a proxy.
Wrapping in custom objects
Instead of using the predefined methods in the HttpApplication interface, it is possible to define a custom interface that extends HttpApplication and to wrap the predefined actions into more business-oriented ones.
Example:
class TestClass {
@Test
public void sampleTest(MyCustomHttpApplication client) {
client
.checkThatAnimalIsInTheDirectory("1", "cat")
.checkThatAnimalIsInTheDirectory("2", "dog");
}
}
@Capability(key = "browserName", value = "pn5-driver8")
public interface MyCustomHttpApplication extends HttpApplication {
default MyCustomHttpApplication checkThatAnimalIsInTheDirectory(
String animalId,
String animalName) {
prepareRestRequest("https://example.com/api/animals", "GET")
.withBasicAuth("user", "password")
.withQueryParam("id", animalId)
.sendAndGetResponse()
.assertStatus(200)
.assertPayloadContains(animalName);
return null;
}
}
This pattern is common for all domains handled by Pumpo#5 and is the recommended coding style to keep tests readable, even for people without deep knowledge of implementation details.
Entry methods
HttpApplication::prepareHttpRequest
| Parameter | Type | Description |
|---|---|---|
| url | String | The target url to call |
| method | String | The HTTP method to use |
Creates a HttpRequestBuilder for the specified URL and method. The builder then allows you to set various parameters of the request before finally calling sendAndGetResponse().
The HttpRequestBuilder is a generic builder. Usually you will prefer the more specialised RestRequestBuilder or SoapRequestBuilder, obtained via the respective entry methods below.
HttpApplication::prepareRestRequest
| Parameter | Type | Description |
|---|---|---|
| url | String | The target url to call |
| method | String | The HTTP method to use |
Creates a RestRequestBuilder for the specified URL and method. This is a specialised builder for REST calls. In addition to all methods inherited from HttpRequestBuilder, it has additional ones that can work with JSON in both the request and the response.
HttpApplication::prepareSoapRequest
| Parameter | Type | Description |
|---|---|---|
| url | String | The target url to call |
Creates a SoapRequestBuilder for the specified URL and method. This is a specialised builder for SOAP calls. In addition to all methods inherited from HttpRequestBuilder, it has additional ones that can work with XML.
Following specific functionality is implemented for SOAP:
- The HTTP method is automatically set to POST.
- If the header for Content-Type is not set manually, it will be set to text/xml; charset=utf-8 once the request is queued.
HTTP request methods
HttpRequestBuilder::withBasicAuth
| Parameter | Type | Description |
|---|---|---|
| user | String | User name in plain |
| password | String | Password in plain |
Instructs the driver to attach an HTTP Basic authentication header. The header will be constructed by the driver and will replace any authentication header if already present.
HttpRequestBuilder::withBearerAuth
| Parameter | Type | Description |
|---|---|---|
| token | String | Token to be used as bearer token |
Instructs the driver to attach an HTTP Bearer authentication header. The header will be constructed by the driver and will replace any authentication header if already present.
HttpRequestBuilder::withBearerAuthResolved
| Parameter | Type | Description |
|---|---|---|
| oAuthEndpoint | String | URL of the endpoint issuing access tokens |
| clientId | String | Identification of the application |
| clientSecret | String | Secret of the application in plain |
| scope | String | Scope for the access token; please check the documentation of the target API to see what scope should be specified |
Uses the driver to obtain an access token from an OAuth endpoint, then instructs the driver to attach an HTTP Bearer authentication header with the obtained token.
To authenticate to the OAuth endpoint, Basic authentication with the client id and client secret will be used.
In this version the token will represent the application only (client credentials grant flow). The client needs to have admin consent for the final resource upfront.
HttpRequestBuilder::withBearerAuthResolved
| Parameter | Type | Description |
|---|---|---|
| oAuthEndpoint | String | URL of the endpoint issuing access tokens |
| clientId | String | Identification of the application |
| clientSecret | String | Secret of the application in plain |
| scope | String | Scope for the access token; please check the documentation of the target API to see what scope should be specified |
| userName | String | Username of the user to impersonate |
| userPassword | String | Password of the user to impersonate in plain |
Uses the driver to obtain an access token from an OAuth endpoint, then instructs the driver to attach an HTTP Bearer authentication header with the obtained token.
To authenticate to the OAuth endpoint, Basic authentication with the client id and client secret will be used.
In this version a user will be impersonated by specifying the user's credentials (resource owner password flow). This flow is not supported by all OAuth providers.
HttpRequestBuilder::withNtlmAuth
| Parameter | Type | Description |
|---|---|---|
| domain | String | The domain of the user authenticated |
| username | String | Username |
| password | String | Password in plain |
| workstation | String | Workstation - In most cases this will not be verified by the server but should represent the hostname (without domain information) from which the authentication is done |
Instructs the driver to proceed with the NTLM authentication flow when accessing the target API. The NTLM authentication flow will be realised on the driver side only.
NTLM authentication involves 3 request/response exchanges with the server. In case the authentication flow fails at some point, the last response will be returned to the client.
HttpRequestBuilder::withClientCertAuth
| Parameter | Type | Description |
|---|---|---|
| certificate | String | Either the path to a file containing an SSL certificate or a chain of certificates, or the file content itself |
| key | String | Either the path to a file containing a private key, or the file content itself |
Instructs the driver to proceed with a client certificate authentication flow when accessing the target API. The client certificate authentication flow will be realised on the driver side only.
In case the authentication flow fails at some point the last response from the server will be returned to the client.
The private key can be either in PKCS1 or PKCS8 format.
HttpRequestBuilder::withHeader
| Parameter | Type | Description |
|---|---|---|
| key | String | The header key (e.g. Content-Type) |
| value | String | The value of the header as plain (e.g. text/xml; charset=utf-8) |
Instructs the driver to attach an HTTP header to the request. Currently, headers are implemented as a Map and do not allow specifying more than one value for a single key. This can be overcome by constructing the value as a comma-separated list of values. This is compliant with the relevant RFC and should be processed by the target server.
HttpRequestBuilder::withQueryParam
| Parameter | Type | Description |
|---|---|---|
| key | String | The parameter name |
| value | String | The parameter value |
Adds a query parameter to the requested URI. Takes care of the URL encoding. If a parameter is set multiple times, only the last value will be retained.
Does not check that the total URI length stays within the allowed size.
HttpRequestBuilder::withPayload
| Parameter | Type | Description |
|---|---|---|
| payload | String | The payload to be sent in plain text |
If the payload is non-empty, it will be sent as the body of the HTTP request to the target server. If not set manually, the HTTP header Content-Length will be set to the size of the resulting body.
The payload should be text only; otherwise, either encode it or use the binary-safe method.
Works with any HTTP method — some combinations (e.g. sending a body with GET) don't make sense but will still be processed.
HttpRequestBuilder::withBinaryPayload
| Parameter | Type | Description |
|---|---|---|
| payload | byte[] | The payload to be sent as plain bytes |
If the payload is non-empty, it will be sent as the body of the HTTP request to the target server. If not set manually, the HTTP header Content-Length will be set to the size of the resulting body.
The content is immediately encoded in base64, which may affect results of methods such as replaceInPayload. The payload is decoded back to a byte array on the driver side. The driver will not set headers such as Content-Disposition automatically.
Works with any HTTP method — some combinations (e.g. sending a body with GET) don't make sense but will still be processed.
HttpRequestBuilder::withPayloadFromFile
| Parameter | Type | Description |
|---|---|---|
| path | String | Path of the text file to be loaded |
The payload will be loaded from a file (as plain text). To load the file, the getResource() method of the classloader attached to the HttpApplication is used. Typically, the path should be specified relative to resource folders.
The file should be text only; otherwise, either encode it or use the binary-safe method.
HttpRequestBuilder::withBinaryPayloadFromFile
| Parameter | Type | Description |
|---|---|---|
| path | String | Path of the binary file to be loaded |
The payload will be loaded from a file (as plain bytes). To load the file, the getResource() method of the classloader attached to the HttpApplication is used. Typically, the path should be specified relative to resource folders.
The content is immediately encoded in base64, which may affect results of methods such as replaceInPayload. The payload is decoded back to a byte array on the driver side. The driver will not set headers such as Content-Disposition automatically.
HttpRequestBuilder::withMultipartFile
| Parameter | Type | Description |
|---|---|---|
| name | String | The form field name of the part |
| data | byte[] | The raw bytes of the file content |
| filename | String | The filename to report for this part |
Adds a file part to a multipart/form-data request body. The Content-Type of the part defaults to application/octet-stream.
The request body is built by the driver as multipart/form-data with a boundary generated automatically. The Content-Type header of the overall request is set to multipart/form-data; boundary=... unless it was already set explicitly via withHeader.
Cannot be combined with withPayload, withBinaryPayload, withPayloadFromFile or withBinaryPayloadFromFile on the same request - a request is either a single body or a multipart one. Mixing them throws an IllegalStateException.
HttpRequestBuilder::withMultipartFile
| Parameter | Type | Description |
|---|---|---|
| name | String | The form field name of the part |
| data | byte[] | The raw bytes of the file content |
| filename | String | The filename to report for this part |
| contentType | String | The Content-Type to report for this part, e.g. "image/png" |
Same as the overload above but lets you specify the Content-Type of the part explicitly instead of defaulting to application/octet-stream.
HttpRequestBuilder::withMultipartText
| Parameter | Type | Description |
|---|---|---|
| name | String | The form field name of the part |
| value | String | The text value of the part |
Adds a plain text field part to a multipart/form-data request body.
Cannot be combined with withPayload, withBinaryPayload, withPayloadFromFile or withBinaryPayloadFromFile on the same request - a request is either a single body or a multipart one. Mixing them throws an IllegalStateException.
Any number of withMultipartFile and withMultipartText calls can be combined on the same request; each is sent as a separate part, in the order they were added.
Example:
client
.prepareRestRequest("https://example.com/api/upload", "POST")
.withMultipartText("description", "invoice scan")
.withMultipartFile("file", fileBytes, "invoice.pdf", "application/pdf")
.sendAndGetResponse()
.assertStatus(200);
HttpRequestBuilder::replaceInUrl
| Parameter | Type | Description |
|---|---|---|
| placeholder | String | Token searched in the URL |
| value | String | Value that will replace the token |
Replaces given token in the URL by the provided value. The String::replace method will be used so no regular expressions are allowed here and all occurrences will be replaced.
HttpRequestBuilder::replaceInPayload
| Parameter | Type | Description |
|---|---|---|
| placeholder | String | Token searched in the payload |
| value | String | Value that will replace the token |
Replaces given token in the payload by the provided value. The String::replace method will be used so no regular expressions are allowed here and all occurrences will be replaced.
In case a binary payload was attached, the replace method will be run over the base64 encoding of the payload.
HttpRequestBuilder::sendAndGetResponse
Completes the builder pattern and sends the request to the driver. Parses the received response as HttpResponse where the fluent interface continues.
REST request methods
RestRequestBuilder inherits all methods from HttpRequestBuilder plus implements the following ones:
RestRequestBuilder::withJsonFromPojoPayload
| Parameter | Type | Description |
|---|---|---|
| payload | Object | Object to be serialised as JSON |
Serialises the provided object to JSON using a Jackson ObjectMapper with no additional settings. The provided object's class may have JSON mappings specified by Jackson annotations. The resulting JSON is then attached as the payload (body) of the HTTP request.
RestRequestBuilder::sendAndGetResponse
Completes the builder pattern and sends the request to the driver. Parses the received response as RestResponse where the fluent interface continues.
SOAP request methods
SoapRequestBuilder inherits all methods from HttpRequestBuilder plus implements the following ones:
SoapRequestBuilder::withAction
| Parameter | Type | Description |
|---|---|---|
| soapAction | Object | Action to be set in the header |
Adds or replaces the header with key SOAPAction with the provided value.
SoapRequestBuilder::withXmlFromPojoPayload
| Parameter | Type | Description |
|---|---|---|
| payload | Object | Object to be serialised as XML |
Serialises the provided object to XML using a JAXB marshaller and puts it in the body of a SOAP envelope. The resulting XML is then attached as the payload (body) of the HTTP request. The JAXB marshaller correctly processes namespaces, which must be specified using XmlElement annotations at every level. SOAP servers are usually permissive and do not require namespaces to be set correctly at every level.
SoapRequestBuilder::sendAndGetResponse
Completes the builder pattern and sends the request to the driver. Parses the received response as SoapResponse where the fluent interface continues.
HTTP Response members
Some methods of HttpResponse allow continuing the fluent interface, while others return specific objects that need to be processed separately. There are also public attributes accessible for manual processing and code simplification.
List of public attributes:
| Attribute | Type | Description |
|---|---|---|
| initialRequest | InitialHttpRequest | Initial request with additional public attributes (url, method, headers, payload) |
| status | int | Status code of the response |
| headers | Map<String,String> | Map of headers where header names are keys |
| payload | String | Body of the response, may be null |
HttpResponse::assertStatus
| Parameter | Type | Description |
|---|---|---|
| status | int | Expected status code |
Asserts that the received response has the provided status code.
HttpResponse::assertBodyIsNotEmpty
Asserts that the received response has a non-empty body.
HttpResponse::assertPayloadContains
| Parameter | Type | Description |
|---|---|---|
| needle | String | Searched text in the payload |
Asserts that the received response payload (body) contains at least one occurrence of the provided string. No regular expressions are allowed in this case.
HttpResponse::assertHeaderReceived
| Parameter | Type | Description |
|---|---|---|
| headerName | String | Name of the header to search |
Asserts that the received response headers contain at least one with the provided name.
HttpResponse::assertHeaderContains
| Parameter | Type | Description |
|---|---|---|
| headerName | String | Key of the header to search |
| value | String | Value to search in the header |
Asserts that the received response has a header with the provided name and that the header content contains the provided value. No regular expressions are allowed here.
HttpResponse::printRequest
Prints the initial request to stdout for debugging purposes.
HttpResponse::printResponse
Prints the response to stdout for debugging purposes.
HttpResponse::andThen
Returns to the initial state where entry methods can be used for the next request without breaking the fluent interface.
REST Response members
RestResponse inherits all members of HttpResponse and adds a few more methods for working with the response payload as JSON.
RestResponse::payloadAs
| Parameter | Type | Description |
|---|---|---|
| poJoClass | Class | Class to use when mapping the JSON to an object |
Returns an object of type PoJoClass deserialised using a Jackson ObjectMapper.
RestResponse::assertThatPayload
| Parameter | Type | Description |
|---|---|---|
| poJoClass | Class | Class to use when mapping the JSON to an object |
Returns an object of type ObjectAssert<PoJoClass> from the AssertJ library that allows running various assertions on the object after deserialising to PoJoClass using Jackson.
RestResponse::payloadBinaryAsByteArray
Returns the payload as plain bytes decoded from Base64.
This method should be used only when the response payload is detected to be binary (e.g. image, document, etc.) and therefore was encoded to Base64 using a heuristic approach.
SOAP Response members
SoapResponse inherits all members of HttpResponse and adds a few more methods for working with the response payload as XML.
SoapResponse::payloadAs
| Parameter | Type | Description |
|---|---|---|
| poJoClass | Class | Class to use when mapping the XML to an object |
Returns an object of type PoJoClass deserialised using a Jackson XmlMapper.
SoapResponse::payloadXmlAs
| Parameter | Type | Description |
|---|---|---|
| poJoClass | Class | Class to use when mapping the XML to an object |
Returns an object of type PoJoClass deserialised using a JAXB unmarshaller. Unlike the previous method, where JsonProperty annotations can be used to map XML elements to PoJo attributes and XML namespaces are ignored, JAXB requires XmlElement annotations with a namespace matching the one used inside the XML at every level. This requires more work but can be more accurate in some cases.
SoapResponse::assertThatPayload
| Parameter | Type | Description |
|---|---|---|
| poJoClass | Class | Class to use when mapping the XML to an object |
Returns an object of type ObjectAssert<PoJoClass> from the AssertJ library that allows running various assertions on the object after deserialising to PoJoClass using Jackson XmlMapper.