package org.jboss.resteasy.test.async;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.client.AsyncInvoker;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.Future;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ComprehensiveJaxrsTest
{
protected Client client;
@Before
public void beforeTest() {
client = new ResteasyClientBuilder().connectionPoolSize(10).build();
}
@After
public void afterTest() {
client.close();
}
protected static String objectsToString(Object... objects) {
StringBuilder sb = new StringBuilder();
for (Object o : objects)
sb.append(o).append(" ");
return sb.toString().trim();
}
public static void logMsg(Object... msg) {
System.out.println(objectsToString(msg));
}
@Test
public void cancelVoidTest()throws Exception {
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> cancel = invokeRequest("cancelvoid?stage=0");
assertStatus(getResponse(suspend), Status.SERVICE_UNAVAILABLE);
assertString(cancel, Resource.TRUE);
}
@Test
public void cancelVoidOnResumedTest()throws Exception {
suspendResumeTest();
Future<Response> cancel = invokeRequest("cancelvoid?stage=1");
assertString(cancel, Resource.FALSE);
}
@Test
public void cancelVoidOnCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> cancel = invokeRequest("cancelvoid?stage=1");
assertString(cancel, Resource.TRUE);
}
@Test
public void resumeCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> resumeCanceled = invokeRequest("resume?stage=1", "");
assertString(resumeCanceled, Resource.FALSE);
}
@Test
public void cancelIntTest()throws Exception {
String seconds = "20";
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> cancel = invokeRequest("cancelretry?stage=0", seconds);
Response response = getResponse(suspend);
assertStatus(response, Status.SERVICE_UNAVAILABLE);
assertString(cancel, Resource.TRUE);
String retry = response.getHeaderString(HttpHeaders.RETRY_AFTER);
assertEquals(seconds, retry, "Unexpected", HttpHeaders.RETRY_AFTER,
"header value received", retry, "expected", seconds);
logMsg("Found expected", HttpHeaders.RETRY_AFTER, "=", retry);
}
protected static void assertEquals(Object expected, Object actual, Object... msg) {
Assert.assertEquals(objectsToString(msg), expected, actual);
}
@Test
public void cancelIntOnResumedTest()throws Exception {
suspendResumeTest();
Future<Response> cancel = invokeRequest("cancelretry?stage=1", "20");
assertString(cancel, Resource.FALSE);
}
@Test
public void cancelIntOnCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> cancel = invokeRequest("cancelretry?stage=1", "20");
assertString(cancel, Resource.TRUE);
}
@Test
public void resumeCanceledIntTest()throws Exception {
cancelIntTest();
Future<Response> resume = invokeRequest("resume?stage=1", "");
assertString(resume, Resource.FALSE);
}
@Test
public void cancelDateTest()throws Exception {
long milis = (System.currentTimeMillis() / 1000) * 1000 + 20000;
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> cancel = invokeRequest("canceldate?stage=0", milis);
Response response = getResponse(suspend);
assertStatus(response, Status.SERVICE_UNAVAILABLE);
assertString(cancel, Resource.TRUE);
String header = response.getHeaderString(HttpHeaders.RETRY_AFTER);
TimeZone timezone = findTimeZoneInDate(header);
Date retry = null;
try {
retry = createDateFormat(timezone).parse(header);
} catch (ParseException e) {
throw new Exception(e);
}
assertEquals(new Date(milis), retry, "Unexpected",
HttpHeaders.RETRY_AFTER, "header value received",
retry.getTime(), "expected", milis);
logMsg("Found expected", HttpHeaders.RETRY_AFTER, "=", header);
}
public static final TimeZone findTimeZoneInDate(String date){
StringBuilder sb = new StringBuilder();
StringBuilder dateBuilder = new StringBuilder(date.trim()).reverse();
int index = 0;
char c;
while ((c = dateBuilder.charAt(index++)) != ' '){
sb.append(c);
}
TimeZone timezone = TimeZone.getTimeZone(sb.reverse().toString());
return timezone;
}
public static final DateFormat createDateFormat(TimeZone timezone){
SimpleDateFormat sdf = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
sdf.setTimeZone(timezone);
return sdf;
}
@Test
public void cancelDateOnResumedTest()throws Exception {
suspendResumeTest();
Future<Response> cancel = invokeRequest("canceldate?stage=1",
System.currentTimeMillis());
assertString(cancel, Resource.FALSE);
}
@Test
public void cancelDateOnCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> cancel = invokeRequest("canceldate?stage=1",
System.currentTimeMillis());
assertString(cancel, Resource.TRUE);
}
@Test
public void resumeCanceledDateTest()throws Exception {
cancelDateTest();
Future<Response> resumeResumed = invokeRequest("resume?stage=1", "");
assertString(resumeResumed, Resource.FALSE);
}
@Test
public void isCanceledWhenCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> is = invokeRequest("iscanceled?stage=1");
assertString(is, Resource.TRUE);
}
@Test
public void isCanceledWhenSuspendedTest()throws Exception {
invokeClear();
invokeRequest("suspend");
Future<Response> is = invokeRequest("iscanceled?stage=0");
assertString(is, Resource.FALSE);
}
@Test
public void isCanceledWhenResumedTest()throws Exception {
suspendResumeTest();
Future<Response> is = invokeRequest("iscanceled?stage=1");
assertString(is, Resource.FALSE);
}
@Test
public void isDoneWhenResumedTest()throws Exception {
suspendResumeTest();
Future<Response> is = invokeRequest("isdone?stage=1");
assertString(is, Resource.TRUE);
}
@Test
public void isDoneWhenSuspendedTest()throws Exception {
invokeClear();
invokeRequest("suspend");
Future<Response> is = invokeRequest("isdone?stage=0");
assertString(is, Resource.FALSE);
}
@Test
public void isDoneWhenCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> is = invokeRequest("isdone?stage=1");
assertString(is, Resource.TRUE);
}
@Test
public void isDoneWhenTimedOutTest()throws Exception {
setTimeoutTest();
Future<Response> is = invokeRequest("isdone?stage=1");
assertString(is, Resource.TRUE);
}
@Test
public void isSuspendedWhenSuspendedTest()throws Exception {
invokeClear();
invokeRequest("suspend");
Future<Response> is = invokeRequest("issuspended?stage=0");
assertString(is, Resource.TRUE);
}
@Test
public void isSuspendedWhenCanceledTest()throws Exception {
cancelVoidTest();
Future<Response> is = invokeRequest("issuspended?stage=1");
assertString(is, Resource.FALSE);
}
@Test
public void isSuspendedWhenResumedTest()throws Exception {
suspendResumeTest();
Future<Response> is = invokeRequest("issuspended?stage=1");
assertString(is, Resource.FALSE);
}
@Test
public void suspendResumeTest()throws Exception {
invokeClear();
String expectedResponse = "Expected response";
Future<Response> suspend = invokeRequest("suspend");
Future<Response> resume = invokeRequest("resume?stage=0",
expectedResponse);
assertString(resume, Resource.TRUE);
assertString(suspend, expectedResponse);
}
@Test
public void resumeAnyJavaObjectInputStreamTest()throws Exception {
invokeClear();
String expectedResponse = "Expected response";
Future<Response> suspend = invokeRequest("suspend");
Future<Response> resume = invokeRequest("resume?stage=0",
new ByteArrayInputStream(expectedResponse.getBytes()));
assertString(resume, Resource.TRUE);
assertString(suspend, expectedResponse);
}
@Test
public void resumeResumedTest()throws Exception {
suspendResumeTest(); // resume & store
Future<Response> resumeResumed = invokeRequest("resume?stage=1", "");
assertString(resumeResumed, Resource.FALSE);
}
@Test
public void resumeWithCheckedExceptionTest()throws Exception {
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> resume = invokeRequest("resumechecked?stage=0");
assertString(resume, Resource.TRUE);
assertException(suspend, IOException.class);
}
@Test
public void resumeWithRuntimeExceptionTest()throws Exception {
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> resume = invokeRequest("resumeruntime?stage=0");
assertString(resume, Resource.TRUE);
assertException(suspend, RuntimeException.class);
}
@Test
public void resumeWithExceptionReturnsFalseWhenResumedTest()throws Exception {
suspendResumeTest();
Future<Response> resume = invokeRequest("resumechecked?stage=1");
assertString(resume, Resource.FALSE);
}
@Test
public void setTimeoutTest()throws Exception {
invokeClear();
logMsg("here 1");
Future<Response> suspend = invokeRequest("suspend");
logMsg("here 2");
Future<Response> setTimeout = invokeRequest("settimeout?stage=0", 200);
logMsg("here 3");
assertStatus(getResponse(setTimeout), Status.NO_CONTENT);
logMsg("here 4");
// WebApplication exception with 503 is caught by ServiceUnavailableExceptionMapper
Response fromMapper = getResponse(suspend);
logMsg("here 5");
assertStatus(fromMapper, Status.REQUEST_TIMEOUT);
String entity = fromMapper.readEntity(String.class);
assertContains(entity, 503);
logMsg("Found expected status 503");
}
@Test
public void updateTimeoutTest()throws Exception {
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> setTimeout = invokeRequest("settimeout?stage=0",
600000);
assertStatus(getResponse(setTimeout), Status.NO_CONTENT);
assertFalse(suspend.isDone(),
"Suspended AsyncResponse already received");
setTimeout = invokeRequest("settimeout?stage=1", 200);
assertStatus(getResponse(setTimeout), Status.NO_CONTENT);
// WebApplication exception with 503 is caught by ServiceUnavailableExceptionMapper
Response fromMapper = getResponse(suspend);
assertStatus(fromMapper, Status.REQUEST_TIMEOUT);
String entity = fromMapper.readEntity(String.class);
assertContains(entity, 503);
logMsg("Found expected status 503");
}
@Test
public void handleTimeOutWaitsForeverTest()throws Exception {
String responseMsg = "handleTimeOutWaitsForeverTest";
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> setTimeout = invokeRequest("timeouthandler?stage=0", 1);
Future<Response> resume = invokeRequest("resume?stage=1", responseMsg);
assertStatus(getResponse(setTimeout), Status.NO_CONTENT);
assertString(resume, Resource.TRUE);
assertString(suspend, responseMsg);
}
@Test
public void handleTimeoutCancelsTest()throws Exception {
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> setTimeout = invokeRequest("timeouthandler?stage=0", 2);
assertStatus(getResponse(setTimeout), Status.NO_CONTENT);
assertStatus(getResponse(suspend), Status.SERVICE_UNAVAILABLE);
Future<Response> resume = invokeRequest("issuspended?stage=1");
assertString(resume, Resource.FALSE);
}
@Test
public void handleTimeoutResumesTest()throws Exception {
invokeClear();
Future<Response> suspend = invokeRequest("suspend");
Future<Response> setTimeout = invokeRequest("timeouthandler?stage=0", 3);
assertStatus(getResponse(setTimeout), Status.NO_CONTENT);
assertString(suspend, Resource.RESUMED);
Future<Response> resume = invokeRequest("issuspended?stage=1");
assertString(resume, Resource.FALSE);
}
protected String getAbsoluteUrl() {
return "http://localhost:8080/resource";
}
private void invokeClear()throws Exception {
Response response = client.target(getAbsoluteUrl()).path("clear").request().get();
Assert.assertEquals(204, response.getStatus());
}
private Future<Response> invokeRequest(String resource) {
AsyncInvoker async = createAsyncInvoker(resource);
Future<Response> future = async.get();
return future;
}
private <T> Future<Response> invokeRequest(String resource, T entity) {
AsyncInvoker async = createAsyncInvoker(resource);
Future<Response> future = async.post(Entity.entity(entity,
MediaType.TEXT_PLAIN_TYPE));
return future;
}
private WebTarget createWebTarget(String resource) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(getAbsoluteUrl() + "/" + resource);
return target;
}
private AsyncInvoker createAsyncInvoker(String resource) {
WebTarget target = createWebTarget(resource);
AsyncInvoker async = target.request().async();
return async;
}
private static Response getResponse(Future<Response> future)throws Exception {
Response response = future.get();
return response;
}
private static void assertStatus(Response response, Response.Status status)
throws Exception {
assertEquals(response.getStatus(), status.getStatusCode(),
"Unexpected status code received", response.getStatus(),
"expected was", status);
logMsg("Found expected status", status);
}
private static void assertString(Future<Response> future, String check)
throws Exception {
Response response = getResponse(future);
assertStatus(response, Status.OK);
String content = response.readEntity(String.class);
assertEquals(check, content, "Unexpected response content", content);
logMsg("Found expected string", check);
}
private static void assertException(Future<Response> future,
Class<? extends Throwable> e)throws Exception {
String clazz = e.getName();
Response response = getResponse(future);
assertStatus(response, Response.Status.NOT_ACCEPTABLE);
assertContains(response.readEntity(String.class), clazz, clazz,
"not thrown");
logMsg(clazz, "has been thrown as expected");
}
public static void assertContains(String string, String substring,
Object... message)throws Exception {
assertTrue(string.contains(substring), message);
}
public static <T> void assertContains(T text, T subtext, Object... message)
throws Exception {
assertContains(text.toString(), subtext.toString(), message);
}
public static void assertTrue(boolean condition, Object... message) {
if (!condition)
Assert.fail(objectsToString(message));
}
public static void //
assertFalse(boolean condition, Object... message)throws Exception {
assertTrue(!condition, message);
}
}