Clover icon

Magnolia Module Cache 5.5.9

  1. Project Clover database Mon Nov 25 2019 16:46:50 CET
  2. Package info.magnolia.module.cache.filter

File CacheFilterTest.java

 

Code metrics

0
420
31
1
804
600
32
0.08
13.55
31
1.03

Classes

Class Line # Actions
CacheFilterTest 112 420 0% 32 44
0.90243990.2%
 

Contributing tests

This file is covered by 22 tests. .

Source view

1    /**
2    * This file Copyright (c) 2008-2018 Magnolia International
3    * Ltd. (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10    * This file is distributed in the hope that it will be
11    * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12    * implied warranty of MERCHANTABILITY or FITNESS FOR A
13    * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14    * Redistribution, except as permitted by whichever of the GPL
15    * or MNA you select, is prohibited.
16    *
17    * 1. For the GPL license (GPL), you can redistribute and/or
18    * modify this file under the terms of the GNU General
19    * Public License, Version 3, as published by the Free Software
20    * Foundation. You should have received a copy of the GNU
21    * General Public License, Version 3 along with this program;
22    * if not, write to the Free Software Foundation, Inc., 51
23    * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24    *
25    * 2. For the Magnolia Network Agreement (MNA), this file
26    * and the accompanying materials are made available under the
27    * terms of the MNA which accompanies this distribution, and
28    * is available at http://www.magnolia-cms.com/mna.html
29    *
30    * Any modifications to this file must keep this entire header
31    * intact.
32    *
33    */
34    package info.magnolia.module.cache.filter;
35   
36    import static info.magnolia.test.TestUtil.enumeration;
37    import static org.junit.Assert.*;
38    import static org.mockito.Matchers.any;
39    import static org.mockito.Matchers.anyLong;
40    import static org.mockito.Matchers.eq;
41    import static org.mockito.Matchers.isA;
42    import static org.mockito.Matchers.isNull;
43    import static org.mockito.Matchers.same;
44    import static org.mockito.Mockito.*;
45   
46    import info.magnolia.cms.cache.CacheConstants;
47    import info.magnolia.cms.core.AggregationState;
48    import info.magnolia.cms.filters.WebContainerResources;
49    import info.magnolia.cms.filters.WebContainerResourcesImpl;
50    import info.magnolia.cms.security.SecurityCallbackFilter;
51    import info.magnolia.cms.security.User;
52    import info.magnolia.cms.util.ServletUtil;
53    import info.magnolia.context.MgnlContext;
54    import info.magnolia.context.WebContext;
55    import info.magnolia.module.ModuleRegistry;
56    import info.magnolia.module.ModuleRegistryImpl;
57    import info.magnolia.module.cache.AbstractCacheTest;
58    import info.magnolia.module.cache.Cache;
59    import info.magnolia.module.cache.CacheFactory;
60    import info.magnolia.module.cache.CachePolicy;
61    import info.magnolia.module.cache.CachePolicyExecutor;
62    import info.magnolia.module.cache.CachePolicyResult;
63    import info.magnolia.module.cache.ContentCachingConfiguration;
64    import info.magnolia.module.cache.ContentCompression;
65    import info.magnolia.module.cache.FlushPolicy;
66    import info.magnolia.module.cache.cachepolicy.Default;
67    import info.magnolia.module.cache.cachepolicy.result.CachePolicyResultProvider;
68    import info.magnolia.module.cache.exception.MgnlLockTimeoutException;
69    import info.magnolia.module.cache.executor.Bypass;
70    import info.magnolia.module.cache.executor.CompositeExecutor;
71    import info.magnolia.module.cache.executor.Store;
72    import info.magnolia.module.cache.executor.UseCache;
73    import info.magnolia.module.cache.util.GZipUtil;
74    import info.magnolia.objectfactory.Components;
75    import info.magnolia.objectfactory.guice.GuiceUtils;
76    import info.magnolia.repository.RepositoryManager;
77    import info.magnolia.test.ComponentsTestUtil;
78    import info.magnolia.voting.DefaultVoting;
79    import info.magnolia.voting.Voting;
80    import info.magnolia.voting.voters.ResponseContentTypeVoter;
81    import info.magnolia.voting.voters.UserAgentVoter;
82    import info.magnolia.voting.voters.VoterSet;
83   
84    import java.io.ByteArrayOutputStream;
85    import java.io.IOException;
86    import java.lang.reflect.Field;
87    import java.util.Arrays;
88    import java.util.Calendar;
89    import java.util.Date;
90    import java.util.Enumeration;
91    import java.util.HashMap;
92    import java.util.Map;
93    import java.util.Set;
94   
95    import javax.servlet.FilterChain;
96    import javax.servlet.FilterConfig;
97    import javax.servlet.ServletException;
98    import javax.servlet.ServletRequest;
99    import javax.servlet.ServletResponse;
100    import javax.servlet.http.HttpServletRequest;
101    import javax.servlet.http.HttpServletResponse;
102   
103    import org.apache.commons.collections4.map.MultiValueMap;
104    import org.junit.After;
105    import org.junit.Before;
106    import org.junit.Ignore;
107    import org.junit.Test;
108   
109    /**
110    * Basic cache filter test.
111    */
 
112    public class CacheFilterTest extends AbstractCacheTest {
113   
114    private static final String CACHE_CONFIG_NAME = "my-config";
115    private static final String originalURL = "/original";
116   
117    private AggregationState aggregationState;
118    private CacheFactory cacheFactory;
119    private CachePolicy cachePolicy;
120    private FlushPolicy flushPolicy;
121    private Cache cache;
122    private CacheFilter filter;
123    private WebContext webContext;
124    private HttpServletRequest request;
125    private HttpServletResponse response;
126    private FilterChain filterChain;
127    private ContentCachingConfiguration cfg;
128   
 
129  22 toggle @Before
130    public void setUp() throws Exception {
131  22 super.setUp();
132  22 ComponentsTestUtil.setImplementation(WebContainerResources.class, WebContainerResourcesImpl.class);
133   
134  22 aggregationState = new AggregationState();
135   
136  22 cacheFactory = mock(CacheFactory.class);
137  22 cachePolicy = mock(CachePolicy.class);
138  22 when(cachePolicy.getTtlVoters()).thenReturn(new VoterSet<CacheResponseWrapper>());
139  22 cache = mock(Cache.class);
140  22 when(cache.getName()).thenReturn(CACHE_CONFIG_NAME);
141  22 request = mock(HttpServletRequest.class);
142  22 response = mock(HttpServletResponse.class);
143  22 filterChain = mock(FilterChain.class);
144  22 flushPolicy = mock(FlushPolicy.class);
145   
146  22 cfg = new ContentCachingConfiguration(cacheModule, null);
147  22 cfg.setName(CACHE_CONFIG_NAME);
148  22 cfg.setCachePolicy(cachePolicy);
149    // add the default executors
150  22 cfg.addExecutor(CachePolicyResult.bypass.getName(), new Bypass());
151  22 cfg.addExecutor(CachePolicyResult.useCache.getName(), new UseCache());
152  22 final Store store = new Store(cacheModule);
153  22 ComponentsTestUtil.setInstance(Voting.class, new DefaultVoting<>());
154  22 final java.util.Map compressibleTypes = new java.util.HashMap();
155  22 compressibleTypes.put("1", "text/html");
156  22 cfg.addExecutor(CachePolicyResult.store.getName(), store);
157  22 cfg.setFlushPolicy(flushPolicy);
158   
159  22 this.addContentCaching(CACHE_CONFIG_NAME, cfg);
160  22 cacheModule.setCacheFactory(cacheFactory);
161   
162  22 HashMap map = new HashMap();
163  22 ContentCompression compression = new ContentCompression();
164  22 cacheModule.setCompression(compression);
165  22 UserAgentVoter voter = new UserAgentVoter();
166  22 voter.addRejected(".*MSIE 6.*");
167  22 voter.setNot(true);
168  22 ResponseContentTypeVoter voter2 = new ResponseContentTypeVoter();
169  22 voter2.addAllowed("text/html");
170  22 voter2.addAllowed("application/x-javascript");
171  22 voter2.addAllowed("application/javascript");
172  22 voter2.addAllowed("text/css");
173  22 voter2.setNot(true);
174  22 compression.setVoters(new VoterSet());
175  22 compression.getVoters().addVoter(voter);
176  22 compression.getVoters().addVoter(voter2);
177   
178    // called by init() : filter.onCacheModuleStart();
179  22 when(cacheFactory.getCache(CACHE_CONFIG_NAME)).thenReturn(cache);
180  22 when(cache.getName()).thenReturn(CACHE_CONFIG_NAME);
181   
182  22 webContext = mock(WebContext.class);
183  22 User user = mock(User.class);
184  22 when(webContext.getAggregationState()).thenReturn(aggregationState);
185  22 when(webContext.getUser()).thenReturn(user);
186  22 MgnlContext.setInstance(webContext);
187   
188  22 filter = new CacheFilter(GuiceUtils.providerForInstance(webContext), cacheModule, cacheMonitor, GuiceUtils.providerForInstance(new CachePolicyResultProvider()));
189  22 filter.setName("cache-filter");
190  22 filter.setDefaultContentCachingConfigurationName(CACHE_CONFIG_NAME);
191  22 filter.init(null);
192    }
193   
 
194  1 toggle @Test(expected = MgnlLockTimeoutException.class)
195    public void lockTimeoutException() throws Exception {
196    // GIVEN
197  1 CachePolicyExecutor executor = mock(CachePolicyExecutor.class);
198  1 Map<String, CachePolicyExecutor> executors = new HashMap<String, CachePolicyExecutor>();
199  1 executors.put(CachePolicyResult.store.getName(), executor);
200  1 cachePolicy = new Default(cacheModule);
201  1 ContentCachingConfiguration cfg = new ContentCachingConfiguration(null, null);
202  1 cfg.setCachePolicy(cachePolicy);
203  1 cfg.setExecutors(executors);
204  1 cfg.setName(CACHE_CONFIG_NAME);
205  1 this.addContentCaching(CACHE_CONFIG_NAME, cfg);
206  1 filter.onCacheModuleStart();
207  1 Exception exception = new MgnlLockTimeoutException(null, null);
208  1 doThrow(exception).when(executor).processCacheRequest(eq(request), eq(response), eq(filterChain), eq(cache), any(CachePolicyResult.class));
209  1 when(webContext.getRequest()).thenReturn(request);
210  1 when(request.getParameterMap()).thenReturn(new HashMap());
211  1 when(request.getMethod()).thenReturn("get");
212   
213    //WHEN
214  1 filter.doFilter(request, response, filterChain);
215    }
216   
 
217  1 toggle @Test(expected = RuntimeException.class)
218    public void otherThanRuntimeException() throws Exception {
219    // GIVEN
220  1 CachePolicyExecutor executor = mock(CachePolicyExecutor.class);
221  1 Map<String, CachePolicyExecutor> executors = new HashMap<String, CachePolicyExecutor>();
222  1 executors.put(CachePolicyResult.store.getName(), executor);
223  1 cachePolicy = new Default(cacheModule);
224  1 cfg = new ContentCachingConfiguration(cacheModule, Components.getComponent(RepositoryManager.class));
225  0 cfg.setCachePolicy(cachePolicy);
226  0 cfg.setExecutors(executors);
227  0 cacheModule.getContentCaching().put(CACHE_CONFIG_NAME, cfg);
228  0 filter.onCacheModuleStart();
229  0 Exception exception = new IOException();
230  0 doThrow(exception).when(executor).processCacheRequest(eq(request), eq(response), eq(filterChain), eq(cache), any(CachePolicyResult.class));
231  0 when(webContext.getRequest()).thenReturn(request);
232  0 when(request.getParameterMap()).thenReturn(new HashMap());
233   
234    // WHEN
235  0 try {
236  0 filter.doFilter(request, response, filterChain);
237    } catch (RuntimeException e) {
238  0 assertEquals(exception, e.getCause());
239  0 throw e;
240    }
241    }
242   
 
243  1 toggle @Test
244    public void testFilterUsesGivenConfigAndCacheName() throws Exception {
245  1 final ModuleRegistry moduleRegistry = new ModuleRegistryImpl();
246  1 ComponentsTestUtil.setInstance(ModuleRegistry.class, moduleRegistry);
247   
248  1 final ContentCachingConfiguration c1 = new ContentCachingConfiguration(null, null);
249  1 c1.setName("wrong");
250  1 final ContentCachingConfiguration c2 = new ContentCachingConfiguration(null, null);
251  1 c2.setName("right-config-name");
252  1 c2.setCacheName("the-cache-name-for-this-config");
 
253  1 toggle final Map<String, ContentCachingConfiguration> ccc = new HashMap<String, ContentCachingConfiguration>() {{
254  1 put("wrong-config", c1);
255  1 put("right-config-name", c2);
256    }};
257  1 cacheModule.setContentCaching(ccc);
258   
259  1 final CacheFactory cacheFactory = mock(CacheFactory.class);
260  1 when(cacheFactory.getCache("right-config-name")).thenReturn(cache);
261  1 cacheModule.setCacheFactory(cacheFactory);
262   
263  1 filter.setName("the-filter-name");
264  1 filter.setDefaultContentCachingConfigurationName("right-config-name");
265   
266  1 moduleRegistry.registerModuleInstance("cache", cacheModule);
267  1 final FilterConfig filterConfig = mock(FilterConfig.class);
268   
269  1 filter.init(filterConfig);
270  1 verify(cacheFactory).getCache("the-cache-name-for-this-config");
271    }
272   
 
273  1 toggle @Test
274    public void test304IsNotCached() throws Exception {
275  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.store, "/dummy", null));
276   
277  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
278  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
279    // the header set by the Store executor
280  1 response.setDateHeader(eq("Last-Modified"), anyLong());
281   
282  1 filterChain.doFilter(same(request), isA(CacheResponseWrapper.class));
283   
284  1 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
285   
286    // this is what Store does if makeCachedEntry() returns null
287  1 cache.put(eq("/dummy"), isNull());
288  1 cache.remove(eq("/dummy"));
289    }
290   
 
291  1 toggle @Test
292    public void testStoresInCacheAndRenders() throws Exception {
293  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.store, "/test-page", null));
294   
295  1 filterChain.doFilter(same(request), isA(CacheResponseWrapper.class));
296   
297  1 response.setDateHeader(eq("Last-Modified"), anyLong());
298    // used to build the writer
299  1 when(response.getCharacterEncoding()).thenReturn("UTF-8");
300    // checks this is not a if-modified request
301  1 when(response.isCommitted()).thenReturn(false);
302  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(new Long(-1));
303   
304    // by default unknown content types are not compresible
305  1 when(response.getContentType()).thenReturn("some content type");
306  1 when(response.getCharacterEncoding()).thenReturn("UTF-8");
307   
308  1 cache.put(eq("/test-page"), isA(ContentCachedEntry.class));
309   
310  1 executeCacheFilterAndVerify();
311    }
312   
 
313  1 toggle @Test
314    public void testStoresCompressedInCacheAndRenders() throws Exception {
315  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.store, "/test-page", null));
316   
317  1 filterChain.doFilter(same(request), isA(CacheResponseWrapper.class));
318   
319  1 response.setDateHeader(eq("Last-Modified"), anyLong());
320    // used to build the writer
321  1 when(response.getCharacterEncoding()).thenReturn("UTF-8");
322    // checks this is not a if-modified request
323  1 when(response.isCommitted()).thenReturn(false);
324  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(new Long(-1));
325   
326    // by default unknown content types are not compresible
327  1 when(response.getContentType()).thenReturn("text/html");
328  1 when(response.getCharacterEncoding()).thenReturn("UTF-8");
329   
330  1 cache.put(eq("/test-page"), isA(ContentCachedEntry.class));
331   
332  1 executeCacheFilterAndVerify();
333    }
334   
 
335  1 toggle @Test
336    public void testBlindlyObeysCachePolicyAndGetsStuffOutOfCacheWhenAskedToDoSo() throws Exception {
337  1 final String dummyContent = "hello i'm a page that was cached";
338   
339  1 final MultiValueMap headers = new MultiValueMap();
340  1 headers.put("Last-Modified", 2000l);
341  1 headers.put("Dummy", "dummy");
342  1 headers.put("Dummy", "dummy2");
343   
344  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 123, headers, System.currentTimeMillis(), originalURL, -1);
345  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
346  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(-1l);
347  1 when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 7.0; Windows NT 5.1)");// .anyTimes();
348  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"));
349  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
350  1 response.setStatus(123);
351  1 when(response.containsHeader("Last-Modified")).thenReturn(false);
352  1 response.addDateHeader("Last-Modified", 2000);
353  1 when(response.containsHeader("Dummy")).thenReturn(false);
354  1 response.addHeader("Dummy", "dummy");
355  1 response.addHeader("Dummy", "dummy2");
356  1 response.setContentType("text/plain");
357  1 response.setCharacterEncoding("ASCII");
358  1 when(response.isCommitted()).thenReturn(false);
359  1 when(response.containsHeader("Content-Encoding")).thenReturn(false);
360  1 response.addHeader("Content-Encoding", "gzip");
361  1 when(response.containsHeader("Content-Encoding")).thenReturn(true);
362  1 response.addHeader("Vary", "Accept-Encoding");
363  1 when(response.containsHeader("Vary")).thenReturn(true);
364  1 response.setContentLength(GZipUtil.gzip(dummyContent.getBytes()).length);
365  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
366  1 response.flushBuffer();
367   
368  1 when(webContext.getResponse()).thenReturn(response);
369   
370  1 executeNoCacheFilterAndVerify();
371   
372  1 assertTrue(Arrays.equals(GZipUtil.gzip(dummyContent.getBytes()), fakedOut.toByteArray()));
373    }
374   
 
375  0 toggle @Ignore
376    @Test
377    public void testIgnoreEncodingAndServeContentFlatWhenUserAgentIsIE6() throws Exception {
378  0 final String dummyContent = "hello i'm a page that was cached";
379   
380  0 final MultiValueMap headers = new MultiValueMap();
381  0 headers.put("Last-Modified", 2000l);
382  0 headers.put("Dummy", "dummy");
383  0 headers.put("Dummy", "dummy2");
384   
385  0 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 123, headers, System.currentTimeMillis(), originalURL, -1);
386  0 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
387  0 when(request.getDateHeader("If-Modified-Since")).thenReturn(-1l);
388  0 when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)");
389  0 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
390  0 response.setStatus(123);
391  0 when(response.containsHeader("Last-Modified")).thenReturn(false);
392  0 response.addDateHeader("Last-Modified", 2000l);
393  0 when(response.containsHeader("Dummy")).thenReturn(false);
394  0 response.addHeader("Dummy", "dummy");
395  0 response.addHeader("Dummy", "dummy2");
396  0 response.setContentType("text/plain");
397  0 response.setCharacterEncoding("ASCII");
398  0 response.setContentLength(32);
399  0 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
400  0 response.flushBuffer();
401   
402  0 when(webContext.getResponse()).thenReturn(response);
403  0 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"));
404  0 when(response.containsHeader("Content-Encoding")).thenReturn(true);
405  0 executeNoCacheFilterAndVerify();
406   
407  0 assertTrue(Arrays.equals(dummyContent.getBytes(), fakedOut.toByteArray()));
408    }
409   
 
410  1 toggle @Test
411    public void testServesUnzippedContentAndRemovesGzipHeadersIfClientDoesNotAcceptGZipEncoding() throws Exception {
412  1 final String dummyContent = "hello i'm a page that was cached";
413   
414  1 final MultiValueMap headers = new MultiValueMap();
415  1 headers.put("Content-Encoding", "gzip");
416  1 headers.put("Vary", "Accept-Encoding");
417  1 headers.put("Dummy", "Some Value");
418  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 123, headers, System.currentTimeMillis(), originalURL, -1);
419  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
420   
421  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(-1l);
422  1 when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 7.0; Windows NT 5.1)");
423  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration());
424  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
425  1 response.setStatus(123);
426  1 when(response.containsHeader("Dummy")).thenReturn(false);
427  1 response.addHeader("Dummy", "Some Value");
428  1 response.setContentType("text/plain");
429  1 response.setCharacterEncoding("ASCII");
430  1 response.setContentLength(dummyContent.length());
431  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
432  1 response.flushBuffer();
433   
434  1 when(webContext.getResponse()).thenReturn(response);
435  1 executeNoCacheFilterAndVerify();
436   
437  1 assertEquals(dummyContent, fakedOut.toString());
438    }
439   
 
440  1 toggle @Test
441    public void testServesGZippedContentIfClientAcceptsGZipEncoding() throws Exception {
442  1 final String dummyContent = "hello i'm a page that was cached";
443  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 123, new MultiValueMap(), System.currentTimeMillis(), originalURL, -1);
444  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
445  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(-1l);
446  1 when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 7.0; Windows NT 5.1)");
447  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"));
448  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
449  1 response.setStatus(123);
450  1 response.setContentType("text/plain");
451  1 response.setCharacterEncoding("ASCII");
452  1 when(response.isCommitted()).thenReturn(false);
453  1 when(response.containsHeader("Content-Encoding")).thenReturn(false);
454  1 response.addHeader("Content-Encoding", "gzip");
455  1 when(response.containsHeader("Content-Encoding")).thenReturn(true);
456  1 response.addHeader("Vary", "Accept-Encoding");
457  1 when(response.containsHeader("Vary")).thenReturn(true);
458  1 byte[] gzipped = GZipUtil.gzip(dummyContent.getBytes());
459  1 response.setContentLength(gzipped.length);
460  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
461  1 response.flushBuffer();
462   
463  1 when(webContext.getResponse()).thenReturn(response);
464  1 executeNoCacheFilterAndVerify();
465   
466  1 assertTrue(Arrays.equals(gzipped, fakedOut.toByteArray()));
467    }
468   
 
469  1 toggle @Test
470    public void testDoesNothingIfCachePolicyCommandsToBypass() throws Exception {
471  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.bypass, "/test-page", null));
472  1 filterChain.doFilter(same(request), same(response));
473   
474  1 executeNoCacheFilterAndVerify();
475    }
476   
 
477  1 toggle @Test
478    public void testJustSends304WithNoBodyIfRequestHeadersAskForIt() throws Exception {
479  1 long timeStampInSeconds = System.currentTimeMillis() / 1000 * 1000;
480   
481  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry("dummy".getBytes(), "text/plain", "ASCII", 200, new MultiValueMap(), timeStampInSeconds, originalURL, -1);
482  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
483  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(timeStampInSeconds); // use some date in the future, so we're ahead of what cachedPage will say
484  1 when(request.getHeader("If-None-Match")).thenReturn(null);
485  1 when(response.isCommitted()).thenReturn(false);
486   
487  1 response.setStatus(304);
488    // since we don't when response.getOuputStream(), we actually assert nothing is written to the body
489   
490  1 executeNoCacheFilterAndVerify();
491    }
492   
 
493  1 toggle @Test
494    public void testJustSends304WithNoBodyIfRequestHeadersAskForItEvenOnCommitedResponse() throws Exception {
495  1 long timeStampInSeconds = System.currentTimeMillis() / 1000 * 1000;
496   
497  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry("dummy".getBytes(), "text/plain", "ASCII", 200, new MultiValueMap(), timeStampInSeconds, originalURL, -1);
498  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
499  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(timeStampInSeconds); // use some date in the future, so we're ahead of what cachedPage will say
500  1 when(request.getHeader("If-None-Match")).thenReturn(null);
501    // the main diff to the test above - response is already committed here and status (304) was set by another executed as indicated in preCacheStatusCode of the ContentCachedEntry
502  1 when(response.isCommitted()).thenReturn(true);
503   
504  1 response.setStatus(304);
505    // since the status is correct we don't when response.getOuputStream(), we actually assert nothing is written to the body
506   
507  1 when(webContext.getResponse()).thenReturn(response);
508  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"));
509  1 when(response.containsHeader("Content-Encoding")).thenReturn(true);
510  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
511  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
512  1 executeNoCacheFilterAndVerify();
513    }
514   
 
515  1 toggle @Test
516    public void testDontJustSends304WithNoBodyIfRequestHeadersAskForItButResponseIsCommitted() throws Exception {
517  1 long timeStampInSeconds = System.currentTimeMillis() / 1000 * 1000;
518   
519  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry("dummy".getBytes(), "text/plain", "ASCII", 200, new MultiValueMap(), timeStampInSeconds, originalURL, -1);
520  1 final byte[] gzipped = GZipUtil.gzip("dummy".getBytes());
521  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
522  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(timeStampInSeconds); // use some date in the future, so we're ahead of what cachedPage will say
523  1 when(request.getHeader("If-None-Match")).thenReturn(null);
524  1 when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 7.0; Windows NT 5.1)");
525  1 when(response.isCommitted()).thenReturn(true);
526    // we can't change status of the already committed response ... the only option left here is to proceed and send the data
527   
528  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"));
529  1 response.setStatus(200);
530  1 response.setContentType("text/plain");
531  1 response.setCharacterEncoding("ASCII");
532  1 when(response.isCommitted()).thenReturn(false);
533  1 when(response.containsHeader("Content-Encoding")).thenReturn(false);
534  1 response.addHeader("Content-Encoding", "gzip");
535  1 when(response.containsHeader("Content-Encoding")).thenReturn(true);
536  1 response.addHeader("Vary", "Accept-Encoding");
537  1 when(response.containsHeader("Vary")).thenReturn(true);
538  1 response.setContentLength(gzipped.length);
539  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
540  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
541  1 response.flushBuffer();
542   
543  1 executeNoCacheFilterAndVerify();
544    }
545   
 
546  1 toggle @Test
547    public void testPageShouldBeServedIfIfNoneMatchHeaderWasPassed() throws Exception {
548  1 final String dummyContent = "i'm a dummy page that was cached earlier on";
549  1 final byte[] gzipped = GZipUtil.gzip(dummyContent.getBytes());
550  1 final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 200, new MultiValueMap(), System.currentTimeMillis(), originalURL, -1);
551  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage));
552  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(System.currentTimeMillis() + 1000); // use some date in the future, so we're ahead of what cachedPage will say
553  1 when(request.getHeader("If-None-Match")).thenReturn("Some value");
554  1 when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 7.0; Windows NT 5.1)");
555  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"));
556   
557  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
558  1 response.setStatus(200);
559  1 response.setContentType("text/plain");
560  1 response.setCharacterEncoding("ASCII");
561  1 when(response.isCommitted()).thenReturn(false);
562  1 when(response.containsHeader("Content-Encoding")).thenReturn(false);
563  1 response.addHeader("Content-Encoding", "gzip");
564  1 when(response.containsHeader("Content-Encoding")).thenReturn(true);
565  1 response.addHeader("Vary", "Accept-Encoding");
566  1 when(response.containsHeader("Vary")).thenReturn(true);
567  1 response.setContentLength(gzipped.length);
568  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
569  1 response.flushBuffer();
570   
571  1 when(webContext.getResponse()).thenReturn(response);
572  1 executeNoCacheFilterAndVerify();
573   
574  1 assertTrue(Arrays.equals(gzipped, fakedOut.toByteArray()));
575    }
576   
 
577  1 toggle @Test
578    public void testRedirectsAreCached() throws Exception {
579  1 final String redirectLocation = "/some-target-location";
580   
581  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.store, "/some-redirect", null));
582   
583  1 filterChain.doFilter(same(request), isA(CacheResponseWrapper.class));
584   
585  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
586   
587  1 response.setDateHeader(eq("Last-Modified"), anyLong());
588  1 response.sendRedirect(redirectLocation);
589  1 when(response.isCommitted()).thenReturn(false);
590  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(new Long(-1));
591  1 response.flushBuffer();
592   
593  1 cache.put(eq("/some-redirect"), isA(CachedRedirect.class));
594   
595  1 executeCacheFilterAndVerify();
596  1 assertEquals("nothing should have been written to the output", 0, fakedOut.size());
597    }
598   
 
599  1 toggle @Test
600    public void testCachedRedirectsAreServed() throws Exception {
601  1 final String redirectLocation = "/some-target-location";
602  1 final CachedRedirect cachedRedirect = new CachedRedirect(333, redirectLocation, originalURL, -1);
603  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/some-redirect", cachedRedirect));
604  1 when(response.isCommitted()).thenReturn(false);
605  1 response.sendRedirect(redirectLocation);
606  1 executeNoCacheFilterAndVerify();
607    }
608   
 
609  1 toggle @Test
610    public void testErrorsAreCached() throws Exception {
611  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.store, "/non-existing", null));
612   
613  1 filterChain.doFilter(same(request), isA(CacheResponseWrapper.class));
614   
615  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
616   
617  1 response.setDateHeader(eq("Last-Modified"), anyLong());
618  1 response.sendError(404);
619    // after sending error, response is committed
620  1 when(response.isCommitted()).thenReturn(true);
621  1 response.flushBuffer();
622   
623  1 cache.put(eq("/non-existing"), isA(CachedError.class));
624   
625  1 executeCacheFilterAndVerify();
626  1 assertEquals("nothing should have been written to the output", 0, fakedOut.size());
627    }
628   
 
629  1 toggle @Test
630    public void testCachedErrorsAreServed() throws Exception {
631  1 final CachedError cachedError = new CachedError(404, originalURL, -1);
632  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/non-existing", cachedError));
633  1 when(response.isCommitted()).thenReturn(false);
634  1 response.sendError(404);
635  1 executeNoCacheFilterAndVerify();
636    }
637   
 
638  1 toggle @Test
639    public void testLastModifiedHeaderCanBeOverriddenByFurtherFiltersAndIsProperlyStoredAndReturned() throws Exception {
640  1 final Calendar cal = Calendar.getInstance();
641  1 cal.set(2008, 7, 8, 18, 0, 0);
642  1 final Date expectedLastModified = cal.getTime();
643   
644  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(
645    new CachePolicyResult(CachePolicyResult.store, "/dummy", null));
646   
647    // the header set by the Store executor
648  1 response.setDateHeader(eq("Last-Modified"), anyLong());
649   
650  1 filterChain.doFilter(same(request), isA(CacheResponseWrapper.class));
651   
652  1 response.setDateHeader(eq("Last-Modified"), eq(expectedLastModified.getTime()));
653  1 when(response.getContentType()).thenReturn("text/html");
654   
655  1 when(request.getHeaders("Accept-Encoding")).thenReturn(new Enumeration() {
656    private boolean has = true;
657   
 
658  0 toggle @Override
659    public boolean hasMoreElements() {
660  0 return has;
661    }
662   
 
663  0 toggle @Override
664    public Object nextElement() {
665  0 has = false;
666  0 return "gzip";
667    }
668    });
669   
670  1 response.addHeader("Content-Encoding", "gzip");
671  1 when(response.containsHeader("Content-Encoding")).thenReturn(true);
672   
673  1 response.addHeader("Vary", "Accept-Encoding");
674  1 when(response.containsHeader("Vary")).thenReturn(true);
675  1 when(response.isCommitted()).thenReturn(false);
676  1 when(request.getDateHeader("If-Modified-Since")).thenReturn(new Long(-1));
677  1 response.flushBuffer();
678   
679    // when setting response headers and when instantiating ContentCachedEntry:
680  1 when(response.getContentType()).thenReturn("some content type");
681  1 when(response.getCharacterEncoding()).thenReturn("UTF-8");
682   
683  1 cache.put(eq("/dummy"), isA(ContentCachedEntry.class));
684   
685  1 executeCacheFilterAndVerify();
686    }
687   
 
688  1 toggle @Test
689    public void testIfWeAreNotWriteContentToResponseTwiceWhenTimeToLiveInSecondsIsZero() throws Exception {
690    // GIVEN
691    // let's first assert the Filter did not forget to register itself
692  1 final Field field = cacheModule.getClass().getDeclaredField("listeners");
693  1 field.setAccessible(true);
694  1 final Set listeners = (Set) field.get(cacheModule);
695  1 assertEquals(1, listeners.size());
696  1 assertEquals(filter, listeners.iterator().next());
697  1 when(webContext.getAggregationState()).thenReturn(aggregationState);
698   
699    // add Store and UseCache executor
700  1 CompositeExecutor storeAndUseCache = new CompositeExecutor();
701  1 storeAndUseCache.addExecutor(new Store(cacheModule));
702  1 storeAndUseCache.addExecutor(new UseCache());
703  1 cacheModule.getContentCaching().get(CACHE_CONFIG_NAME).addExecutor(CachePolicyResult.store.getName(), storeAndUseCache);
704   
705  1 when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.store, "/test-page", null));
706   
707  1 StringBuffer buffer = new StringBuffer("/test-page");
708  1 when(request.getRequestURL()).thenReturn(buffer);
709   
710  1 FilterChain filterChain = new FilterChain() {
711   
 
712  1 toggle @Override
713    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
714  1 ((CacheResponseWrapper) response).addHeader(CacheConstants.HEADER_CACHE_CONTROL, CacheConstants.HEADER_VALUE_NO_CACHE);
715  1 response.getOutputStream().print("Test content");
716    }
717    };
718   
719  1 when(webContext.getResponse()).thenReturn(response);
720  1 when(request.getHeader("User-Agent")).thenReturn("Mozilla/5.0 Chrome/18.0.1025.151 Safari/535.19");
721  1 when(response.getContentType()).thenReturn("text/plain");
722  1 when(response.getCharacterEncoding()).thenReturn("UTF-8");
723  1 when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar"), enumeration("foo", "gzip", "bar"));
724  1 when(response.containsHeader("Content-Encoding")).thenReturn(false, true);
725  1 when(response.containsHeader("Vary")).thenReturn(true);
726  1 final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream();
727  1 when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut));
728   
729    // WHEN
730  1 filter.doFilter(request, response, filterChain);
731   
732    // THEN
733  1 assertTrue(GZipUtil.isGZipped(fakedOut.toByteArray()));
734  1 assertEquals(32, fakedOut.size());
735  1 assertEquals("Test content", new String(GZipUtil.ungzip(fakedOut.toByteArray())));
736   
737  1 verify(cacheFactory).getCache(CACHE_CONFIG_NAME);
738  1 verify(cachePolicy).shouldCache(cache, aggregationState, flushPolicy);
739    }
740   
 
741  1 toggle @Test
742    public void bypassAlreadyWrappedResponse() {
743    //GIVEN
744  1 HttpServletResponse response = new SecurityCallbackFilter.StatusSniffingResponseWrapper(mock(CacheResponseWrapper.class));
745  1 when(webContext.getResponse()).thenReturn(response);
746   
747    //WHEN
748  1 boolean bypasses = filter.bypasses(request);
749   
750    //THEN
751  1 assertTrue(bypasses);
752    }
753   
 
754  1 toggle @Test
755    public void bypassErrorRequests() {
756    //GIVEN
757  1 when(request.getAttribute(ServletUtil.ERROR_REQUEST_STATUS_CODE_ATTRIBUTE)).thenReturn(404);
758   
759    //WHEN
760  1 boolean bypasses = filter.bypasses(request);
761   
762    //THEN
763  1 assertTrue(bypasses);
764    }
765   
 
766  5 toggle private void executeCacheFilterAndVerify() throws IOException, ServletException, NoSuchFieldException, IllegalAccessException {
767    // let's first assert the Filter did not forget to register itself
768  5 final Field field = cacheModule.getClass().getDeclaredField("listeners");
769  5 field.setAccessible(true);
770  5 final Set listeners = (Set) field.get(cacheModule);
771  5 assertEquals(1, listeners.size());
772  5 assertEquals(filter, listeners.iterator().next());
773  5 when(webContext.getAggregationState()).thenReturn(aggregationState);
774   
775    // and now get down to the real business
776  5 StringBuffer buffer = new StringBuffer("some/path");
777  5 when(request.getRequestURL()).thenReturn(buffer);
778  5 filter.doFilter(request, response, filterChain);
779   
780  5 verify(cacheFactory).getCache(CACHE_CONFIG_NAME);
781  5 verify(cachePolicy).shouldCache(cache, aggregationState, flushPolicy);
782    }
783   
 
784  10 toggle private void executeNoCacheFilterAndVerify() throws IOException, ServletException, NoSuchFieldException, IllegalAccessException {
785    // let's first assert the Filter did not forget to register itself
786  10 final Field field = cacheModule.getClass().getDeclaredField("listeners");
787  10 field.setAccessible(true);
788  10 final Set listeners = (Set) field.get(cacheModule);
789  10 assertEquals(1, listeners.size());
790  10 assertEquals(filter, listeners.iterator().next());
791   
792    // and now get down to the real business
793  10 filter.doFilter(request, response, filterChain);
794   
795  10 verify(cacheFactory).getCache(CACHE_CONFIG_NAME);
796  10 verify(cachePolicy).shouldCache(cache, aggregationState, flushPolicy);
797    }
798   
 
799  22 toggle @After
800    public void tearDown() throws Exception {
801  22 super.tearDown();
802  22 MgnlContext.setInstance(null);
803    }
804    }