PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/atlassian-plugins-webresource-common/src/test/java/com/atlassian/plugin/servlet/cache/filter/ETagCachingFilterTest.java

https://bitbucket.org/atlassian/atlassian-plugins
Java | 134 lines | 87 code | 18 blank | 29 comment | 0 complexity | 727f8f00dea3204f5c1f92d9dbc759e5 MD5 | raw file
  1. package com.atlassian.plugin.servlet.cache.filter;
  2. import com.atlassian.plugin.servlet.cache.model.CacheableResponse;
  3. import com.atlassian.plugin.servlet.cache.model.ETagToken;
  4. import org.junit.Test;
  5. import javax.servlet.*;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. import java.nio.charset.StandardCharsets;
  10. import java.util.Optional;
  11. import java.util.function.Consumer;
  12. import static com.atlassian.plugin.servlet.util.function.FailableConsumer.wrapper;
  13. import static com.google.common.net.HttpHeaders.IF_NONE_MATCH;
  14. import static java.lang.Void.TYPE;
  15. import static java.util.Arrays.stream;
  16. import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
  17. import static org.mockito.Mockito.*;
  18. public class ETagCachingFilterTest {
  19. /**
  20. * Representation of a real URI used to serve a batch javascript file.
  21. */
  22. private static final String BATCH_JS_FILE_URL = new StringBuilder("https://localhost:8080")
  23. .append("/s/27a5fa98bce4cd77093c8b11702e0c82-CDN/-airmqf/814000/cb046e2294e854f76e4eff70d7d3d5ce/02192afb1120393751ce10f9f002f180")
  24. .append("/_/download/contextbatch/js/_super/batch.js")
  25. .toString();
  26. /**
  27. * WHEN If-None-Match matches the ETag generated from a Response body.
  28. * THEN set the ETag header with the current ETag and set Http Status code to 304.
  29. * AND an empty response body.
  30. */
  31. @Test
  32. public void testWhenIfNoneMatchHeaderMatchesETag_shouldNotSetResponseBodyAndNotModifiedStatusCode() throws IOException, ServletException {
  33. final String ifNoneMatchHeader = "ceb57c850c288bc938f074693631a2dc"; // Hash representation of the following responseContentBody.
  34. final String responseContentBody = "<script>console.log('Hello World!')</script>";
  35. final Consumer<HttpServletResponse> verifier = wrapper((response) -> {
  36. verify(response.getOutputStream(), never()).flush();
  37. verify(response.getOutputStream(), never()).write(responseContentBody.getBytes());
  38. verify(response, never()).setContentLength(responseContentBody.length());
  39. verify(response, times(1)).setStatus(SC_NOT_MODIFIED);
  40. });
  41. test(ifNoneMatchHeader, responseContentBody, verifier);
  42. }
  43. /**
  44. * WHEN If-None-Match does not match the ETag generated from a response body.
  45. * THEN set the ETag header with the current ETag.
  46. * AND set the response body with the current content.
  47. */
  48. @Test
  49. public void testWhenIfNoneMatchHeaderDoesNotMatchETag_shouldSetResponseBody() throws IOException, ServletException {
  50. final String ifNoneMatchHeader = "ceb57c850c288bc938f074693631a2d4"; // Hash that does not represents the following responseContentBody.
  51. final String responseContentBody = "<script>console.log('Hello Universe!')</script>";
  52. final Consumer<HttpServletResponse> verifier = wrapper((httpServletResponse) -> {
  53. verify(httpServletResponse, times(1)).setContentLength(responseContentBody.length());
  54. verify(httpServletResponse.getOutputStream(), times(1)).write(responseContentBody.getBytes());
  55. verify(httpServletResponse.getOutputStream(), times(1)).flush();
  56. });
  57. test(ifNoneMatchHeader, responseContentBody, verifier);
  58. }
  59. /**
  60. * WHEN If-None-Match is null.
  61. * THEN set the ETag header with the current ETag.
  62. * AND set the response body with the current content.
  63. */
  64. @Test
  65. public void testWhenThereIsNotAnyIfNoneMatchHeader_shouldSetResponseBody() throws IOException, ServletException {
  66. final String ifNoneMatchHeader = null;
  67. final String responseContentBody = "<script>console.log('Hello World!')</script>";
  68. final Consumer<HttpServletResponse> verifier = wrapper((response) -> {
  69. verify(response, times(1)).setContentLength(responseContentBody.length());
  70. verify(response.getOutputStream(), times(1)).write(responseContentBody.getBytes());
  71. verify(response.getOutputStream(), times(1)).flush();
  72. });
  73. test(ifNoneMatchHeader, responseContentBody, verifier);
  74. }
  75. private void test(final String ifNoneMatchHeader,
  76. final String responseContentBody,
  77. final Consumer<HttpServletResponse> verifier) throws IOException, ServletException {
  78. //given
  79. final HttpServletRequest request = mock(HttpServletRequest.class);
  80. when(request.getHeader(IF_NONE_MATCH)).thenReturn(ifNoneMatchHeader);
  81. when(request.getRequestURI()).thenReturn(BATCH_JS_FILE_URL);
  82. final HttpServletResponse response = mock(HttpServletResponse.class);
  83. final ServletOutputStream responseBodyOutputStream = mock(ServletOutputStream.class);
  84. when(response.getOutputStream()).thenReturn(responseBodyOutputStream);
  85. final FilterChain filterChain = mockFilterChain(responseContentBody);
  86. //when
  87. new ETagCachingFilter().doFilter(request, response, filterChain);
  88. //then
  89. verifier.accept(response);
  90. }
  91. /**
  92. * <p>Generates a mock of {@link FilterChain} which will modify the content body of a {@link CacheableResponse}
  93. * to have its value as the response content body when {@link FilterChain#doFilter(ServletRequest, ServletResponse)} is called.
  94. *
  95. * @return The mocked version of a {@link FilterChain}.
  96. * @throws IOException Error while writing to the response output stream.
  97. * @throws ServletException Error while performing the filtering.
  98. */
  99. private FilterChain mockFilterChain(final String responseContentBody) throws IOException, ServletException {
  100. final FilterChain filterChain = mock(FilterChain.class);
  101. doAnswer(invocation -> {
  102. final Optional<CacheableResponse> possibleCacheableResponse = stream(invocation.getArguments())
  103. .filter(argument -> argument instanceof CacheableResponse)
  104. .map(argument -> (CacheableResponse) argument)
  105. .findAny();
  106. possibleCacheableResponse
  107. .ifPresent(wrapper((cacheableResponse) -> cacheableResponse
  108. .getOutputStream()
  109. .write(responseContentBody.getBytes())));
  110. return TYPE;
  111. })
  112. .when(filterChain)
  113. .doFilter(any(ServletRequest.class), any(ServletResponse.class));
  114. return filterChain;
  115. }
  116. }