package org.testfun.jee.runner.jaxrs;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import static org.fest.assertions.Assertions.assertThat;
public class RestRequest {
private String uri;
private int port;
private String basicCreds;
private MediaType contentType = MediaType.APPLICATION_XML_TYPE;
private MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
private Object body;
private Map<String, Object> queryParams = new HashMap<>();
private Response.Status expectedStatus;
private String expectedLocationUri;
public RestRequest(String uri, int port) {
this.uri = uri;
this.port = port;
}
public RestRequest accept(MediaType acceptMediaType) {
contentType = acceptMediaType;
return this;
}
public RestRequest header(String key, Object value) {
headers.add(key, value);
return this;
}
public RestRequest body(Object body) {
this.body = body;
return this;
}
public RestRequest withFormParam(String name, String value) {
String entry = name + "=" + value;
this.body = body == null ? entry : body.toString() + "&" + entry;
return this;
}
public RestRequest basicAuth(String userName, String password) {
try {
basicCreds = URLEncoder.encode(userName, "UTF-8") + ":" + URLEncoder.encode(password, "UTF-8");
} catch (UnsupportedEncodingException e) {
basicCreds = userName + ":" + password;
}
return this;
}
public RestRequest queryParam(String param, Object value) {
queryParams.put(param, value);
return this;
}
public RestRequest expectStatus(Response.Status expectedStatus) {
this.expectedStatus = expectedStatus;
return this;
}
public RestRequest expectLocation(String expectedLocationUri) {
this.expectedLocationUri = expectedLocationUri;
return this;
}
public String get() {
return doHttpMethod("GET");
}
public String put() {
return doHttpMethod("PUT");
}
public String post() {
return doHttpMethod("POST");
}
public String delete() {
return doHttpMethod("DELETE");
}
private String doHttpMethod(String method) {
String baseUri = basicCreds != null ? "http://" + basicCreds + "@localhost" : "http://localhost";
UriBuilder path = UriBuilder.fromUri(baseUri).port(port).path(uri);
WebTarget webTarget = ClientBuilder.newBuilder().build().target(path.build());
for (Map.Entry<String, Object> entry: queryParams.entrySet()) {
webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
}
Response response;
try {
if (body != null) {
response = webTarget.request().headers(headers).build(method, Entity.entity(body, contentType)).invoke();
} else {
response = webTarget.request().headers(headers).build(method).invoke();
}
} catch (Exception e) {
throw new JaxRsException(method + " failed", e);
}
assertExpectedStatus(response);
assertLocation(response);
return toString(response);
}
@SuppressWarnings("unchecked")
private String toString(Response response) {
Response.Status responseStatus = Response.Status.fromStatusCode(response.getStatus());
if (responseStatus == Response.Status.NO_CONTENT) {
return null;
}
if (responseStatus.getFamily() != Response.Status.Family.SUCCESSFUL && responseStatus != expectedStatus) {
throw new ClientErrorException(response);
} else {
return response.readEntity(String.class);
}
}
private void assertExpectedStatus(Response response) {
if (expectedStatus != null) {
Response.Status responseStatus = Response.Status.fromStatusCode(response.getStatus());
assertThat(responseStatus)
.as("Expected response with status " + expectedStatus.getStatusCode() + " (" + expectedStatus + ") but got response with status " + response.getStatus() + " (" + responseStatus + ")")
.isEqualTo(expectedStatus);
}
}
private void assertLocation(Response response) {
if (expectedLocationUri != null) {
String actualLocation = response.getLocation().toString();
assertThat(actualLocation).
as("Expected location '" + expectedLocationUri + "' but got " + actualLocation).
contains(expectedLocationUri);
}
}
}