Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
play.test.FunctionalTest Maven / Gradle / Ivy
package play.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.nio.channels.Channels;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;
import org.apache.commons.lang.ArrayUtils;
import org.junit.Before;
import com.ning.http.client.FluentCaseInsensitiveStringsMap;
import com.ning.http.client.multipart.FilePart;
import com.ning.http.client.multipart.MultipartBody;
import com.ning.http.client.multipart.MultipartUtils;
import com.ning.http.client.multipart.Part;
import com.ning.http.client.multipart.StringPart;
import play.Invoker;
import play.Invoker.InvocationContext;
import play.classloading.enhancers.ControllersEnhancer.ControllerInstrumentation;
import play.mvc.ActionInvoker;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Http.Request;
import play.mvc.Http.Response;
import play.mvc.Router.ActionDefinition;
import play.mvc.Scope.RenderArgs;
/**
* Application tests support
*/
public abstract class FunctionalTest extends BaseTest {
public static final String APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded";
public static final String MULTIPART_FORM_DATA = "multipart/form-data";
private static Map savedCookies; // cookies stored
// between calls
private static Map renderArgs = new HashMap<>();
@Before
public void clearCookies() {
savedCookies = null;
}
// Requests
public static Response GET(Object url) {
return GET(newRequest(), url);
}
/**
* sends a GET request to the application under tests.
*
* @param url
* relative url such as "/products/1234"
* @param followRedirect
* indicates if request have to follow redirection (status 302)
* @return the response
*/
public static Response GET(Object url, boolean followRedirect) {
Response response = GET(url);
if (Http.StatusCode.FOUND == response.status && followRedirect) {
Http.Header redirectedTo = response.headers.get("Location");
String location = redirectedTo.value();
if (location.contains("http")) {
java.net.URL redirectedUrl = null;
try {
redirectedUrl = new java.net.URL(redirectedTo.value());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
response = GET(redirectedUrl.getPath());
} else {
response = GET(location);
}
}
return response;
}
/**
* sends a GET request to the application under tests.
*
* @param request
* @param url
* relative url such as "/products/1234"
* @return the response
*/
public static Response GET(Request request, Object url) {
String path = "";
String queryString = "";
String turl = url.toString();
if (turl.contains("?")) {
path = turl.substring(0, turl.indexOf("?"));
queryString = turl.substring(turl.indexOf("?") + 1);
} else {
path = turl;
}
request.method = "GET";
request.url = turl;
request.path = path;
request.querystring = queryString;
request.body = new ByteArrayInputStream(new byte[0]);
if (savedCookies != null)
request.cookies = savedCookies;
return makeRequest(request);
}
// convenience methods
public static Response POST(Object url) {
return POST(url, APPLICATION_X_WWW_FORM_URLENCODED, "");
}
public static Response POST(Request request, Object url) {
return POST(request, url, APPLICATION_X_WWW_FORM_URLENCODED, "");
}
public static Response POST(Object url, String contenttype, String body) {
return POST(newRequest(), url, contenttype, body);
}
public static Response POST(Request request, Object url, String contenttype, String body) {
return POST(request, url, contenttype, new ByteArrayInputStream(body.getBytes()));
}
public static Response POST(Object url, String contenttype, InputStream body) {
return POST(newRequest(), url, contenttype, body);
}
/**
* Sends a POST request to the application under tests.
*
* @param request
* @param url
* relative url such as "/products/1234"
* @param contenttype
* content-type of the request
* @param body
* posted data
* @return the response
*/
public static Response POST(Request request, Object url, String contenttype, InputStream body) {
String path = "";
String queryString = "";
String turl = url.toString();
if (turl.contains("?")) {
path = turl.substring(0, turl.indexOf("?"));
queryString = turl.substring(turl.indexOf("?") + 1);
} else {
path = turl;
}
request.method = "POST";
request.contentType = contenttype;
request.url = turl;
request.path = path;
request.querystring = queryString;
request.body = body;
if (savedCookies != null)
request.cookies = savedCookies;
return makeRequest(request);
}
/**
* Sends a POST request to the application under tests as a multipart form.
* Designed for file upload testing.
*
* @param url
* relative url such as "/products/1234"
* @param parameters
* map of parameters to be posted
* @param files
* map containing files to be uploaded
* @return the response
*/
public static Response POST(Object url, Map parameters, Map files) {
return POST(newRequest(), url, parameters, files);
}
public static Response POST(Object url, Map parameters) {
return POST(newRequest(), url, parameters, new HashMap());
}
public static Response POST(Request request, Object url, Map parameters, Map files) {
List parts = new ArrayList<>();
for (String key : parameters.keySet()) {
StringPart stringPart = new StringPart(key, parameters.get(key), request.contentType, Charset.forName(request.encoding));
parts.add(stringPart);
}
for (Map.Entry entry : files.entrySet()) {
File file = entry.getValue();
if (file != null) {
Part filePart = new FilePart(entry.getKey(), entry.getValue());
parts.add(filePart);
}
}
MultipartBody requestEntity = null;
/*
* ^1 MultipartBody::read is not working (if parts.isEmpty() == true)
* byte[] array = null;
**/
_ByteArrayOutputStream baos = null;
try {
requestEntity = MultipartUtils.newMultipartBody(parts, new FluentCaseInsensitiveStringsMap());
request.headers.putAll(ArrayUtils
.toMap(new Object[][] { { "content-type", new Http.Header("content-type", requestEntity.getContentType()) } }));
long contentLength = requestEntity.getContentLength();
if (contentLength < Integer.MIN_VALUE || contentLength > Integer.MAX_VALUE) {
throw new IllegalArgumentException(contentLength + " cannot be cast to int without changing its value.");
}
// array = new byte[(int) contentLength]; // ^1
// requestEntity.read(ByteBuffer.wrap(array)); // ^1
baos = new _ByteArrayOutputStream((int) contentLength);
requestEntity.transferTo(0, Channels.newChannel(baos));
} catch (IOException e) {
throw new RuntimeException(e);
}
// InputStream body = new ByteArrayInputStream(array != null ? array :
// new byte[0]); // ^1
InputStream body = new ByteArrayInputStream(baos != null ? baos.getByteArray() : new byte[0]);
return POST(request, url, MULTIPART_FORM_DATA, body);
}
public static Response PUT(Object url, String contenttype, String body) {
return PUT(newRequest(), url, contenttype, body);
}
/**
* Sends a PUT request to the application under tests.
*
* @param request
* @param url
* relative url such as "/products/1234"
* @param contenttype
* content-type of the request
* @param body
* data to send
* @return the response
*/
public static Response PUT(Request request, Object url, String contenttype, String body) {
String path = "";
String queryString = "";
String turl = url.toString();
if (turl.contains("?")) {
path = turl.substring(0, turl.indexOf("?"));
queryString = turl.substring(turl.indexOf("?") + 1);
} else {
path = turl;
}
request.method = "PUT";
request.contentType = contenttype;
request.url = turl;
request.path = path;
request.querystring = queryString;
request.body = new ByteArrayInputStream(body.getBytes());
if (savedCookies != null)
request.cookies = savedCookies;
return makeRequest(request);
}
public static Response DELETE(String url) {
return DELETE(newRequest(), url);
}
/**
* Sends a DELETE request to the application under tests.
*
* @param request
* @param url
* relative url eg. "/products/1234"
* @return the response
*/
public static Response DELETE(Request request, Object url) {
String path = "";
String queryString = "";
String turl = url.toString();
if (turl.contains("?")) {
path = turl.substring(0, turl.indexOf("?"));
queryString = turl.substring(turl.indexOf("?") + 1);
} else {
path = turl;
}
request.method = "DELETE";
request.url = turl;
request.path = path;
request.querystring = queryString;
if (savedCookies != null)
request.cookies = savedCookies;
request.body = new ByteArrayInputStream(new byte[0]);
return makeRequest(request);
}
public static void makeRequest(final Request request, final Response response) {
final CountDownLatch actionCompleted = new CountDownLatch(1);
TestEngine.functionalTestsExecutor.submit(new Invoker.Invocation() {
@Override
public void execute() throws Exception {
renderArgs.clear();
ActionInvoker.invoke(request, response);
if (RenderArgs.current().data != null) {
renderArgs.putAll(RenderArgs.current().data);
}
}
@Override
public void onSuccess() throws Exception {
try {
super.onSuccess();
} finally {
onActionCompleted();
}
}
@Override
public void onException(Throwable e) {
try {
super.onException(e);
} finally {
onActionCompleted();
}
}
private void onActionCompleted() {
actionCompleted.countDown();
}
@Override
public InvocationContext getInvocationContext() {
ActionInvoker.resolve(request, response);
return new InvocationContext(Http.invocationType, request.invokedMethod.getAnnotations(),
request.invokedMethod.getDeclaringClass().getAnnotations());
}
});
try {
if (!actionCompleted.await(30, TimeUnit.SECONDS)) {
throw new TimeoutException("Request did not complete in time");
}
if (savedCookies == null) {
savedCookies = new HashMap<>();
}
for (Map.Entry e : response.cookies.entrySet()) {
// If Max-Age is unset, browsers discard on exit; if
// 0, they discard immediately.
if (e.getValue().maxAge == null || e.getValue().maxAge > 0) {
savedCookies.put(e.getKey(), e.getValue());
} else {
// cookies with maxAge zero still remove a previously
// existing cookie,
// like PLAY_FLASH.
savedCookies.remove(e.getKey());
}
}
response.out.flush();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static Response makeRequest(Request request) {
Response response = newResponse();
makeRequest(request, response);
if (response.status == 302) { // redirect
// if Location-header is pressent, fix it to "look like" a
// functional-test-url
Http.Header locationHeader = response.headers.get("Location");
if (locationHeader != null) {
String locationUrl = locationHeader.value();
if (locationUrl.startsWith("http://localhost/")) {
locationHeader.values.clear();
locationHeader.values.add(locationUrl.substring(16));// skip
// 'http://localhost'
}
}
}
return response;
}
public static Response newResponse() {
Response response = new Response();
response.out = new ByteArrayOutputStream();
return response;
}
public static Request newRequest() {
Request request = Request.createRequest(null, "GET", "/", "", null, null, null, null, false, 80, "localhost", false, null, null);
return request;
}
// Assertions
/**
* Asserts a 2OO Success response
*
* @param response
* server response
*/
public static void assertIsOk(Response response) {
assertStatus(200, response);
}
/**
* Asserts a 404 (not found) response
*
* @param response
* server response
*/
public static void assertIsNotFound(Response response) {
assertStatus(404, response);
}
/**
* Asserts response status code
*
* @param status
* expected HTTP response code
* @param response
* server response
*/
public static void assertStatus(int status, Response response) {
assertEquals("Response status ", (Object) status, response.status);
}
/**
* Exact equality assertion on response body
*
* @param content
* expected body content
* @param response
* server response
*/
public static void assertContentEquals(String content, Response response) {
assertEquals(content, getContent(response));
}
/**
* Asserts response body matched a pattern or contains some text.
*
* @param pattern
* a regular expression pattern or a regular text, ( which must
* be escaped using Pattern.quote)
* @param response
* server response
*/
public static void assertContentMatch(String pattern, Response response) {
Pattern ptn = Pattern.compile(pattern);
boolean ok = ptn.matcher(getContent(response)).find();
assertTrue("Response content does not match '" + pattern + "'", ok);
}
/**
* Verify response charset encoding, as returned by the server in the
* Content-Type header. Be aware that if no charset is returned, assertion
* will fail.
*
* @param charset
* expected charset encoding such as "utf-8" or "iso8859-1".
* @param response
* server response
*/
public static void assertCharset(String charset, Response response) {
int pos = response.contentType.indexOf("charset=") + 8;
String responseCharset = (pos > 7) ? response.contentType.substring(pos).toLowerCase() : "";
assertEquals("Response charset", charset.toLowerCase(), responseCharset);
}
/**
* Verify the response content-type
*
* @param contentType
* expected content-type without any charset extension, such as
* "text/html"
* @param response
* server response
*/
public static void assertContentType(String contentType, Response response) {
String responseContentType = response.contentType;
assertNotNull("Response contentType missing", responseContentType);
assertTrue("Response contentType unmatched : '" + contentType + "' !~ '" + responseContentType + "'",
responseContentType.startsWith(contentType));
}
/**
* Exact equality assertion on a response header value
*
* @param headerName
* header to verify. case-insensitive
* @param value
* expected header value
* @param response
* server response
*/
public static void assertHeaderEquals(String headerName, String value, Response response) {
assertNotNull("Response header " + headerName + " missing", response.headers.get(headerName));
assertEquals("Response header " + headerName + " mismatch", value, response.headers.get(headerName).value());
}
/**
* obtains the response body as a string
*
* @param response
* server response
* @return the response body as an utf-8 string
*/
public static String getContent(Response response) {
byte[] data = response.out.toByteArray();
try {
return new String(data, response.encoding);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
}
public static Object renderArgs(String name) {
return renderArgs.get(name);
}
// Utils
public void sleep(int seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected static URL reverse() {
ControllerInstrumentation.stopActionCall();
ActionDefinition actionDefinition = new ActionDefinition();
Controller._currentReverse.set(actionDefinition);
return new URL(actionDefinition);
}
public static class URL {
ActionDefinition actionDefinition;
URL(ActionDefinition actionDefinition) {
this.actionDefinition = actionDefinition;
}
@Override
public String toString() {
return actionDefinition.url;
}
}
public static final class _ByteArrayOutputStream extends ByteArrayOutputStream {
public _ByteArrayOutputStream(int size) {
super(size);
}
public byte[] getByteArray() {
return this.buf;
}
}
}