io.neba.core.resourcemodels.caching.RequestScopedResourceModelCacheTest.java Source code

Java tutorial

Introduction

Here is the source code for io.neba.core.resourcemodels.caching.RequestScopedResourceModelCacheTest.java

Source

/**
 * Copyright 2013 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 the "License";
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
    
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/

package io.neba.core.resourcemodels.caching;

import io.neba.core.util.Key;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.FilterChain;
import javax.servlet.ServletResponse;
import java.util.concurrent.Callable;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

/**
 * @author Olaf Otto
 */
@RunWith(MockitoJUnitRunner.class)
public class RequestScopedResourceModelCacheTest {
    @Mock
    private Resource resource;
    @Mock
    private SlingHttpServletRequest request;
    @Mock
    private RequestPathInfo requestPathInfo;
    @Mock
    private ServletResponse response;
    @Mock
    private FilterChain chain;
    @Mock
    private Logger logger;

    private Object model = new Object();
    private Class<?> modelType = Object.class;

    private Object cachedModel;

    @InjectMocks
    private RequestScopedResourceModelCache testee;

    @Before
    public void setUp() throws Exception {
        doReturn("GET").when(this.request).getMethod();
        doReturn(this.requestPathInfo).when(this.request).getRequestPathInfo();
    }

    @Test
    public void testLookupOfModel() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                withResourcePath("/junit/test/1");

                lookupModelFromCache();
                assertModelIsNotInCache();
                putModelInCache();

                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testLookupOfDifferentResourcePaths() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withResourcePath("/junit/test/1");
                putModelInCache();

                withResourcePath("/junit/test/2");
                lookupModelFromCache();
                assertModelIsNotInCache();

                withResourcePath("/junit/test/1");
                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsNotSelectorSensitiveWithoutSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withSelector("new.selector");

                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsNotSuffixSensitiveWithoutSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withSuffix("/newSuffix");

                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsNotPagePathSensitiveWithoutSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withPath("/old/path");

                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withPath("/new/path");

                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsNotSensitiveToQueryStringWithoutSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withQueryString("new=parameter");

                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsSelectorSensitiveInSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withSafeMode();
                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withSelector("new.selector");

                lookupModelFromCache();
                assertModelIsNotInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsSuffixSensitiveInSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withSafeMode();
                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withSuffix("/newSuffix");

                lookupModelFromCache();
                assertModelIsNotInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsPagePathSensitiveInSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withSafeMode();
                withPath("/old/path");

                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withPath("/new/path");

                lookupModelFromCache();
                assertModelIsNotInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsNotSensitiveToPathChangesBelowCurrentPageInSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withSafeMode();
                withPath("/a/page");

                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withPath("/a/page/jcr:content/parsys");

                lookupModelFromCache();
                assertModelWasFoundInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheIsSensitiveToQueryStringInSafeMode() throws Exception {
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                withSafeMode();
                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                assertModelWasFoundInCache();

                withQueryString("new=parameter");

                lookupModelFromCache();
                assertModelIsNotInCache();
                return null;
            }
        });
    }

    @Test
    public void testCacheGracefullyHandlesMissingRequestContextDuringCacheWrite() throws Exception {
        withoutRequestAttributes();
        putModelInCache();
    }

    @Test
    public void testCacheGracefullyHandlesMissingRequestContextDuringCacheRead() throws Exception {
        withoutRequestAttributes();
        lookupModelFromCache();
        assertModelIsNotInCache();
    }

    @Test
    public void testStatisticsEnabledForAnyRequestUri() throws Exception {
        enableStatistics();
        withRequestUri("/arbitrary/request/uri.html");

        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                withResourcePath("/junit/test/1");
                putModelInCache();
                lookupModelFromCache();
                lookupModelFromCache();
                return null;
            }
        });

        verifyStatisticsReportLogs("Request scoped cache report for GET /arbitrary/request/uri.html:\n"
                + "Hits: 2, misses: 0, writes: 1, total number of items: 1\n"
                + "Key {/junit/test/1, class java.lang.Object}: misses=0, hits=2, writes=1\n");
        verifyNothingElseIsReported();
    }

    @Test
    public void testStatisticsEnabledForSpecificRequestUri() throws Exception {
        withStatisticsRestrictedTo("/junit/test/2");
        withRequestUri("/junit/test/1.html");
        enableStatistics();

        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                withResourcePath("/junit/test/1");
                putModelInCache();
                return null;
            }
        });

        verifyNothingIsReported();

        withRequestUri("/junit/test/2.html");
        request(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                withResourcePath("/junit/test/2");
                putModelInCache();
                return null;
            }
        });

        verifyStatisticsReportLogs("Request scoped cache report for GET /junit/test/2.html:\n"
                + "Hits: 0, misses: 0, writes: 1, total number of items: 1\n"
                + "Key {/junit/test/2, class java.lang.Object}: misses=0, hits=0, writes=1\n");
        verifyNothingElseIsReported();
    }

    private void verifyNothingIsReported() {
        verify(this.logger, never()).info(anyString());
    }

    private void withStatisticsRestrictedTo(String urlFragment) {
        this.testee.setRestrictStatisticsTo(urlFragment);
    }

    private void verifyNothingElseIsReported() {
        verifyNoMoreInteractions(logger);
    }

    private void verifyStatisticsReportLogs(String msg) {
        verify(logger).info(msg);
    }

    private void enableStatistics() {
        this.testee.setEnableStatistics(true);
    }

    private void withSafeMode() {
        this.testee.setSafeMode(true);
    }

    private void withQueryString(String queryString) {
        when(this.request.getQueryString()).thenReturn(queryString);
    }

    private void withPath(String path) {
        when(this.requestPathInfo.getResourcePath()).thenReturn(path);
    }

    private void withSuffix(String suffix) {
        when(this.requestPathInfo.getSuffix()).thenReturn(suffix);
    }

    private void withSelector(String selectorString) {
        when(this.requestPathInfo.getSelectorString()).thenReturn(selectorString);
    }

    private void assertModelWasFoundInCache() {
        assertThat(this.cachedModel).isEqualTo(this.model);
    }

    private void putModelInCache() {
        testee.put(this.resource, this.model, new Key(this.resource.getPath(), this.modelType));
    }

    private void assertModelIsNotInCache() {
        assertThat(this.cachedModel).isNull();
    }

    private void lookupModelFromCache() throws Exception {
        cachedModel = testee.get(new Key(this.resource.getPath(), this.modelType));
    }

    private void withResourcePath(String path) {
        doReturn(path).when(this.resource).getPath();
    }

    private void withRequestUri(String uri) {
        doReturn(uri).when(this.request).getRequestURI();
    }

    private void request(final Callable<Object> callable) throws Exception {
        doAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                return callable.call();
            }
        }).when(this.chain).doFilter(eq(this.request), eq(this.response));
        this.testee.doFilter(this.request, this.response, this.chain);
    }

    private void withoutRequestAttributes() {
        RequestContextHolder.setRequestAttributes(null);
    }
}