package org.jboss.resteasy.test.asynch; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.test.asynch.resource.AsynchBasicResource; import org.jboss.resteasy.utils.PermissionUtil; import org.jboss.resteasy.utils.PortProviderUtil; import org.jboss.resteasy.utils.TestUtil; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.client.Entity; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import java.lang.reflect.ReflectPermission; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.PropertyPermission; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.jboss.resteasy.utils.PortProviderUtil.generateURL; /** * @tpSubChapter Asynchronous RESTEasy * @tpChapter Integration tests * @tpTestCaseDetails Basic asynchronous test for "resteasy.async.job.service.max.job.results" property. * @tpSince RESTEasy 3.0.16 */ @RunWith(Arquillian.class) public class AsynchBasicTest { private static org.jboss.logging.Logger logger = org.jboss.logging.Logger.getLogger(AsynchBasicTest.class); public static CountDownLatch latch; private static final String DEFAULT_DEPLOYMENT = "AsynchBasicTestBasic"; private static final String ONE_MAX_DEPLOYMENT = "AsynchBasicTestOne"; private static final String TEN_MAX_DEPLOYMENT = "AsynchBasicTestTen"; public static Archive<?> deploy(String deploymentName, String maxSize) { WebArchive war = TestUtil.prepareArchive(deploymentName); war.addClass(PortProviderUtil.class); war.addClass(TestUtil.class); Map<String, String> contextParam = new HashMap<>(); contextParam.put("resteasy.async.job.service.enabled", "true"); if (maxSize != null) { contextParam.put("resteasy.async.job.service.max.job.results", maxSize); } // Arquillian in the deployment war.addAsManifestResource(PermissionUtil.createPermissionsXmlAsset(new ReflectPermission("suppressAccessChecks"), new RuntimePermission("accessDeclaredMembers"), new PropertyPermission("arquillian.*", "read")), "permissions.xml"); return TestUtil.finishContainerPrepare(war, contextParam, AsynchBasicResource.class); } @Deployment(name = DEFAULT_DEPLOYMENT) public static Archive<?> deployDefault() { return deploy(DEFAULT_DEPLOYMENT, null); } @Deployment(name = ONE_MAX_DEPLOYMENT) public static Archive<?> deployOne() { return deploy(ONE_MAX_DEPLOYMENT, "1"); } @Deployment(name = TEN_MAX_DEPLOYMENT) public static Archive<?> deployTen() { return deploy(TEN_MAX_DEPLOYMENT, "10"); } private ResteasyClient initClient() { return new ResteasyClientBuilder() .socketTimeout(5, TimeUnit.SECONDS) .connectionCheckoutTimeout(5, TimeUnit.SECONDS) .establishConnectionTimeout(5, TimeUnit.SECONDS) .build(); } /** * @tpTestDetails Test oneway=true query parameter * @tpSince RESTEasy 3.0.16 */ @Test @OperateOnDeployment(DEFAULT_DEPLOYMENT) public void testOneway() throws Exception { ResteasyClient client = initClient(); Response response = null; try { latch = new CountDownLatch(1); long start = System.currentTimeMillis(); response = client.target(generateURL("?oneway=true", DEFAULT_DEPLOYMENT)).request().put(Entity.entity("content", "text/plain")); //response = request.put(); long end = System.currentTimeMillis() - start; Assert.assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus()); Assert.assertTrue(end < 1000); Assert.assertTrue("Request was not sent correctly", latch.await(2, TimeUnit.SECONDS)); } finally { response.close(); client.close(); } } /** * @tpTestDetails Use default value of resteasy.async.job.service.max.job.results * @tpSince RESTEasy 3.0.16 */ @Test @OperateOnDeployment(DEFAULT_DEPLOYMENT) public void testAsynchBasic() throws Exception { final int MAX = 4; ResteasyClient client = initClient(); latch = new CountDownLatch(1); long start = System.currentTimeMillis(); Response response = client.target(generateURL("?asynch=true", DEFAULT_DEPLOYMENT)).request().post(Entity.entity("content", "text/plain")); @SuppressWarnings("unused") long end = System.currentTimeMillis() - start; Assert.assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus()); String jobUrl = response.getHeaderString(HttpHeaders.LOCATION); response.close(); response = client.target(jobUrl).request().get(); Assert.assertTrue("Request was not sent correctly", latch.await(3, TimeUnit.SECONDS)); response.close(); // there's a lag between when the latch completes and the executor // registers the completion of the call for (int i = 0; i <= MAX; i++) { response = client.target(jobUrl).request().get(); Thread.sleep(1000); if (HttpServletResponse.SC_OK == response.getStatus()) { Assert.assertEquals("Wrong response content", "content", response.readEntity(String.class)); response.close(); break; } response.close(); if (i == MAX) { Assert.fail("Expected response with status code 200"); } } // test its still there response = client.target(jobUrl).request().get(); Thread.sleep(1000); Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus()); Assert.assertEquals("Wrong response content", "content", response.readEntity(String.class)); response.close(); // delete and test delete response = client.target(jobUrl).request().delete(); Assert.assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); response.close(); response = client.target(jobUrl).request().get(); Thread.sleep(1000); Assert.assertEquals(HttpServletResponse.SC_GONE, response.getStatus()); response.close(); client.close(); } /** * @tpTestDetails Set value of resteasy.async.job.service.max.job.results to 1. Try to store to cache to items. * @tpSince RESTEasy 3.0.16 */ @Test @OperateOnDeployment(ONE_MAX_DEPLOYMENT) public void testAsynchOne() throws Exception { ResteasyClient client = initClient(); // test cache size latch = new CountDownLatch(1); Response response = client.target(generateURL("?asynch=true", ONE_MAX_DEPLOYMENT)).request().post(Entity.entity("content", "text/plain")); Assert.assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus()); String jobUrl1 = response.getHeaderString(HttpHeaders.LOCATION); Assert.assertTrue("Request was not sent correctly", latch.await(3, TimeUnit.SECONDS)); response.close(); latch = new CountDownLatch(1); response = client.target(generateURL("?asynch=true", ONE_MAX_DEPLOYMENT)).request().post(Entity.entity("content", "text/plain")); Assert.assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus()); String jobUrl2 = response.getHeaderString(HttpHeaders.LOCATION); Assert.assertTrue("Request was not sent correctly", latch.await(3, TimeUnit.SECONDS)); Assert.assertTrue("There are only one response for two requests", !jobUrl1.equals(jobUrl2)); response.close(); response = client.target(jobUrl1).request().get(); Thread.sleep(1000); Assert.assertEquals("Response should be gone, but server still remember it", HttpServletResponse.SC_GONE, response.getStatus()); response.close(); // test its still there response = client.target(jobUrl2).request().get(); Thread.sleep(1000); Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus()); Assert.assertEquals("Wrong content of response", "content", response.readEntity(String.class)); response.close(); // delete and test delete response = client.target(jobUrl2).request().delete(); Assert.assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); response.close(); response = client.target(jobUrl2).request().get(); Assert.assertEquals(HttpServletResponse.SC_GONE, response.getStatus()); response.close(); } /** * @tpTestDetails Test default value of resteasy.server.cache.maxsize. It should be 100. Try to store 110 items to cache. 10 items should be gone. * @tpSince RESTEasy 3.0.16 */ @Test @OperateOnDeployment(DEFAULT_DEPLOYMENT) public void testAsynchMaxSizeDefault() throws Exception { ResteasyClient client = initClient(); ArrayList<String> jobs = new ArrayList<>(); for (int i = 0; i < 110; i++) { // test cache size latch = new CountDownLatch(1); Response response = client.target(generateURL("?asynch=true", DEFAULT_DEPLOYMENT)).request().post(Entity.entity("content", "text/plain")); Assert.assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus()); String jobUrl = response.getHeaderString(HttpHeaders.LOCATION); logger.info(i + ": " + jobUrl); jobs.add(jobUrl); response.close(); Thread.sleep(50); } Thread.sleep(2000); for (int i = 0; i < 10; i++) { Response response = client.target(jobs.get(i)).request().get(); logger.info(i + " (" + jobs.get(i) + "): get " + response.getStatus() + ", expected: " + HttpServletResponse.SC_GONE); Assert.assertEquals("Response should be gone, but server still remember it", HttpServletResponse.SC_GONE, response.getStatus()); response.close(); Thread.sleep(50); } for (int i = 10; i < 110; i++) { Response response = client.target(jobs.get(i)).request().get(); logger.info(i + " (" + jobs.get(i) + "): get " + response.getStatus() + ", expected: " + HttpServletResponse.SC_OK); Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus()); Assert.assertEquals("Wrong content of response", "content", response.readEntity(String.class)); response.close(); Thread.sleep(50); } } /** * @tpTestDetails Set value of resteasy.server.cache.maxsize to 10. Try to restore item from cache. * @tpSince RESTEasy 3.0.16 */ @Test @OperateOnDeployment(TEN_MAX_DEPLOYMENT) public void testAsynchTen() throws Exception { ResteasyClient client = initClient(); // test readAndRemove latch = new CountDownLatch(1); Response response = client.target(generateURL("?asynch=true", TEN_MAX_DEPLOYMENT)).request().post(Entity.entity("content", "text/plain")); Assert.assertEquals(HttpServletResponse.SC_ACCEPTED, response.getStatus()); String jobUrl2 = response.getHeaderString(HttpHeaders.LOCATION); Assert.assertTrue("Request was not sent correctly", latch.await(3, TimeUnit.SECONDS)); response.close(); Thread.sleep(50); // test its still there response = client.target(jobUrl2).request().post(Entity.text(new String())); Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus()); Assert.assertEquals("Wrong content of response", "content", response.readEntity(String.class)); response.close(); Thread.sleep(50); response = client.target(jobUrl2).request().get(); Thread.sleep(1000); Assert.assertEquals(HttpServletResponse.SC_GONE, response.getStatus()); response.close(); } }