package org.jboss.resteasy.test.cache; import static org.jboss.resteasy.test.TestPortProvider.generateURL; import java.io.File; import java.util.Hashtable; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import org.apache.commons.io.FileUtils; import org.jboss.resteasy.annotations.cache.Cache; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.plugins.cache.server.ServerCacheFeature; import org.jboss.resteasy.plugins.server.netty.NettyJaxrsServer; import org.jboss.resteasy.spi.ResteasyDeployment; import org.jboss.resteasy.test.TestPortProvider; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** * RESTEASY-1105 * * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="ron.sigal@jboss.com">Ron Sigal</a> * @version $Revision: 1 $ * * * Copyright Mar 25, 2015 */ public class PersistentServerCacheTest { private static int count = 0; private static int plainCount = 0; private static int htmlCount = 0; private static NettyJaxrsServer server; protected static ResteasyDeployment deployment; protected static Dispatcher dispatcher; protected static Client client; @Path("/cache") public static class TestResource { @GET @Produces("text/plain") @Cache(maxAge = 2) public String get() { count++; return "hello world" + count; } @PUT @Consumes("text/plain") public void put(String val) { } @GET @Produces("text/plain") @Path("accepts") @Cache(maxAge = 2) public String getPlain() { plainCount++; return "plain" + plainCount; } @GET @Produces("text/html") @Path("accepts") @Cache(maxAge = 2) public String getHtml() { htmlCount++; return "html" + htmlCount; } @GET @Produces("text/plain") @Path("stuff") @Cache(maxAge = 2) public String getStuff() { count++; return "stuff"; } @GET @Produces("text/plain") @Path("vary") @Cache(maxAge = 2) public Response getVary(@HeaderParam("X-Test-Vary") @DefaultValue("default") String testVary) { count++; return Response.ok(testVary).header(HttpHeaders.VARY, "X-Test-Vary").header("X-Count", count).build(); } } @Path("/cache") public static interface MyProxy { @GET @Produces("text/plain") public String get(); } @BeforeClass public static void beforeClass() { client = ClientBuilder.newClient(); } @AfterClass public static void afterClass() { client.close(); } @Before public void before() throws Exception { FileUtils.deleteDirectory(new File("target/TestCache")); Hashtable<String,String> initParams = new Hashtable<String,String>(); Hashtable<String,String> contextParams = new Hashtable<String,String>(); contextParams.put("server.request.cache.infinispan.config.file", "infinispan.xml"); contextParams.put("server.request.cache.infinispan.cache.name", "TestCache"); server = new NettyJaxrsServer(); server.setPort(TestPortProvider.getPort()); server.setRootResourcePath("/"); server.start(); deployment = server.getDeployment(); dispatcher = deployment.getDispatcher(); deployment.getProviderFactory().property("server.request.cache.infinispan.config.file", "infinispan.xml"); deployment.getProviderFactory().property("server.request.cache.infinispan.cache.name", "TestCache"); deployment.getProviderFactory().register(ServerCacheFeature.class); deployment.getRegistry().addPerRequestResource(TestResource.class); } @After public void after() throws Exception { FileUtils.deleteDirectory(new File("target/TestCache")); server.stop(); server = null; dispatcher = null; deployment = null; } @Test public void testNoCacheHitValidation() throws Exception { // test that after a cache expiration NOT MODIFIED is still returned if matching etags count = 0; String etag = null; { Builder request = client.target(generateURL("/cache/stuff")).request(); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "stuff"); } Thread.sleep(2000); { Builder request = client.target(generateURL("/cache/stuff")).request(); request.header(HttpHeaders.IF_NONE_MATCH, etag); Response response = request.get(); Assert.assertEquals(Response.Status.NOT_MODIFIED.getStatusCode(), response.getStatus()); Assert.assertEquals(2, count); response.close(); } } @Test public void testCache() throws Exception { count = 0; String etag = null; { Builder request = client.target(generateURL("/cache")).request(); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "hello world" + 1); } { Builder request = client.target(generateURL("/cache")).request(); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "hello world" + 1); } // test if-not-match { Builder request = client.target(generateURL("/cache")).request(); request.header(HttpHeaders.IF_NONE_MATCH, etag); Response response = request.get(); Assert.assertEquals(Response.Status.NOT_MODIFIED.getStatusCode(), response.getStatus()); response.close(); } Thread.sleep(2000); { Builder request = client.target(generateURL("/cache")).request(); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "hello world" + 2); } { Builder request = client.target(generateURL("/cache")).request(); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "hello world" + 2); } { Builder request = client.target(generateURL("/cache")).request(); Response response = request.put(Entity.entity("yo", "text/plain")); response.close(); } { Builder request = client.target(generateURL("/cache")).request(); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "hello world" + 3); } } @Test public void testAccepts() throws Exception { count = 0; plainCount = 0; htmlCount = 0; String etag = null; { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/plain"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "plain" + 1); } { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/plain"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "plain" + 1); } { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/html"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "html" + 1); } { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/html"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "html" + 1); } } @Test public void testPreferredAccepts() throws Exception { count = 0; plainCount = 0; htmlCount = 0; String etag = null; { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/plain"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "plain" + 1); } { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/html"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "html" + 1); } { Builder request = client.target(generateURL("/cache/accepts")).request(); request.header(HttpHeaders.ACCEPT, "text/html;q=0.5, text/plain"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "plain" + 1); } { Builder request = client.target(generateURL("/cache/accepts")).request(); request.header(HttpHeaders.ACCEPT, "text/plain;q=0.5, text/html"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "html" + 1); } } @Test public void testPreferredButNotCachedAccepts() throws Exception { count = 0; plainCount = 0; htmlCount = 0; String etag = null; { Builder request = client.target(generateURL("/cache/accepts")).request().accept("text/plain"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "plain" + 1); } // we test that the preferred can be handled { Builder request = client.target(generateURL("/cache/accepts")).request(); request.header(HttpHeaders.ACCEPT, "text/plain;q=0.5, text/html"); Response response = request.get(); Assert.assertEquals(200, response.getStatus()); String cc = response.getHeaderString(HttpHeaders.CACHE_CONTROL); Assert.assertNotNull(cc); etag = response.getHeaderString(HttpHeaders.ETAG); Assert.assertNotNull(etag); Assert.assertEquals(response.readEntity(String.class), "html" + 1); } } @Test public void testVary() throws Exception { int cachedCount; { Builder request = client.target(generateURL("/cache/vary")).request(); Response foo = request.accept("text/plain").header("X-Test-Vary", "foo").get(); Assert.assertEquals("foo", foo.readEntity(String.class)); cachedCount = Integer.parseInt(foo.getHeaderString("X-Count")); } { Builder request = client.target(generateURL("/cache/vary")).request(); Response bar = request.accept("text/plain").header("X-Test-Vary", "bar").get(); Assert.assertEquals("bar", bar.readEntity(String.class)); } { Builder request = client.target(generateURL("/cache/vary")).request(); Response foo = request.accept("text/plain").header("X-Test-Vary", "foo").get(); Assert.assertEquals("foo", foo.readEntity(String.class)); int currentCount = Integer.parseInt(foo.getHeaderString("X-Count")); Assert.assertEquals(cachedCount, currentCount); } } }