package com.vtence.molecule.middlewares; import com.vtence.molecule.Request; import com.vtence.molecule.Response; import org.junit.Test; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.concurrent.ExecutionException; import static com.vtence.molecule.http.HttpDate.httpDate; import static com.vtence.molecule.http.HttpMethod.GET; import static com.vtence.molecule.http.HttpMethod.HEAD; import static com.vtence.molecule.http.HttpMethod.POST; import static com.vtence.molecule.http.HttpStatus.CREATED; import static com.vtence.molecule.http.HttpStatus.NOT_MODIFIED; import static com.vtence.molecule.http.HttpStatus.OK; import static com.vtence.molecule.testing.ResponseAssert.assertThat; public class ConditionalGetTest { ConditionalGet conditional = new ConditionalGet(); Request request = new Request().method(GET); Response response = new Response(); @Test public void sendsNotModifiedWithoutMessageBodyWhenGettingEntityWhoseRepresentationHasNotChanged() throws Exception { request.header("If-None-Match", "12345678"); conditional.handle(request, response); response.header("ETag", "12345678") .contentType("text/plain").contentLength(32).body("response content") .done(); assertNoExecutionError(); assertThat(response).hasStatus(NOT_MODIFIED) .hasBodySize(0) .hasNoHeader("Content-Type") .hasNoHeader("Content-Length"); } @Test public void leavesResponseUnchangedOnGetWhenCacheValidatorsAreMissing() throws Exception { conditional.handle(request, response); response.body("response content").done(); assertNoExecutionError(); assertThat(response).hasStatus(OK) .hasBodyText("response content"); } @Test public void ignoresCacheValidatorsOnGetIfResponseNotOK() throws Exception { request.header("If-None-Match", "12345678"); conditional.handle(request, response); response.status(CREATED).header("ETag", "12345678").done(); assertNoExecutionError(); assertThat(response).hasStatus(CREATED); } @Test public void appliesConditionalLogicToHeadRequestsAsWell() throws Exception { request.method(HEAD).header("If-None-Match", "12345678"); conditional.handle(request, response); response.header("ETag", "12345678").done(); assertNoExecutionError(); assertThat(response).hasStatus(NOT_MODIFIED); } @Test public void ignoresNonGetOrHeadRequests() throws Exception { request.method(POST).header("If-None-Match", "12345678"); conditional.handle(request, response); response.header("ETag", "12345678").done(); assertNoExecutionError(); assertThat(response).hasStatus(OK); } @Test public void sendsNotModifiedWhenGettingEntityWhichHasNotBeenModifiedSinceLastServed() throws Exception { final String lastModification = httpDate(Instant.now()); request.header("If-Modified-Since", lastModification); conditional.handle(request, response); response.header("Last-Modified", lastModification).done(); assertNoExecutionError(); assertThat(response).hasStatus(NOT_MODIFIED); } @Test public void leavesResponseUnchangedWhenEntityHasNotBeenModifiedButETagIndicatesItIsNotCurrent() throws Exception { final String lastModification = httpDate(Instant.now()); request.header("If-None-Match", "87654321") .header("If-Modified-Since", lastModification); conditional.handle(request, response); response.header("ETag", "12345678").header("Last-Modified", lastModification).done(); assertNoExecutionError(); assertThat(response).hasStatus(OK); } @Test public void leavesResponseUnchangedWhenEntityWasModifiedButETagIndicatesItIsCurrent() throws Exception { request.header("If-None-Match", "12345678") .header("If-Modified-Since", httpDate(oneHourAgo())); conditional.handle(request, response); response.header("ETag", "12345678") .header("Last-Modified", httpDate(Instant.now())).done(); assertNoExecutionError(); assertThat(response).hasStatus(OK); } @Test public void leavesResponseUnchangedIfModifiedSinceDateFormatIsNotSupported() throws Exception { request.header("If-Modified-Since", "???"); conditional.handle(request, response); response.header("Last-Modified", httpDate(Instant.now())).done(); assertNoExecutionError(); assertThat(response).hasStatus(OK); } private Instant oneHourAgo() { return Instant.now().minus(1, ChronoUnit.HOURS); } private void assertNoExecutionError() throws ExecutionException, InterruptedException { response.await(); } }