/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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 org.apereo.portal.portlet.rendering;
import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.portlet.CacheControl;
import javax.portlet.PortletException;
import javax.servlet.http.HttpServletRequest;
import junit.framework.Assert;
import org.apache.pluto.container.PortletContainer;
import org.apache.pluto.container.PortletContainerException;
import org.apache.pluto.container.PortletWindow;
import org.apereo.portal.api.portlet.PortletDelegationLocator;
import org.apereo.portal.events.IPortletExecutionEventFactory;
import org.apereo.portal.portlet.container.cache.CacheState;
import org.apereo.portal.portlet.container.cache.CachedPortletData;
import org.apereo.portal.portlet.container.cache.CachedPortletResourceData;
import org.apereo.portal.portlet.container.cache.IPortletCacheControlService;
import org.apereo.portal.portlet.om.IPortletDefinition;
import org.apereo.portal.portlet.om.IPortletEntity;
import org.apereo.portal.portlet.om.IPortletWindow;
import org.apereo.portal.portlet.om.IPortletWindowId;
import org.apereo.portal.portlet.registry.IPortletWindowRegistry;
import org.apereo.portal.url.IPortalRequestInfo;
import org.apereo.portal.url.IUrlSyntaxProvider;
import org.apereo.portal.utils.web.PortletHttpServletRequestWrapper;
import org.apereo.portal.utils.web.PortletHttpServletResponseWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Tests for {@link PortletRendererImpl}.
*
*/
@RunWith(MockitoJUnitRunner.class)
public class PortletRendererImplTest {
@InjectMocks private PortletRendererImpl portletRenderer = new PortletRendererImpl();
@Mock private IUrlSyntaxProvider urlSyntaxProvider;
@Mock private IPortletExecutionEventFactory portalEventFactory;
@Mock private IPortletCacheControlService portletCacheControlService;
@Mock private IPortletWindowRegistry portletWindowRegistry;
@Mock private PortletContainer portletContainer;
@Mock private PortletDelegationLocator portletDelegationLocator;
@Mock private IPortletWindowId portletWindowId;
@Mock private IPortletWindow portletWindow;
@Mock private IPortletEntity portletEntity;
@Mock private IPortletDefinition portletDefinition;
@Mock private PortletWindow plutoPortletWindow;
@Mock private IPortalRequestInfo portalRequestInfo;
private final String portletFname = "MyPortlet";
/** Does common setup of mock options needed for portlet execution */
protected void setupPortletExecutionMocks(MockHttpServletRequest request) {
when(portletWindowRegistry.getPortletWindow(
isA(HttpServletRequest.class), eq(portletWindowId)))
.thenReturn(portletWindow);
when(portletWindowRegistry.getPortletWindow(request, portletWindowId))
.thenReturn(portletWindow);
when(portletWindow.getPortletWindowId()).thenReturn(portletWindowId);
when(portletWindow.getRenderParameters())
.thenReturn(Collections.<String, String[]>emptyMap());
when(portletWindow.getPlutoPortletWindow()).thenReturn(plutoPortletWindow);
when(portletWindow.getPortletEntity()).thenReturn(portletEntity);
when(portletEntity.getPortletDefinition()).thenReturn(portletDefinition);
when(portletDefinition.getFName()).thenReturn(portletFname);
when(urlSyntaxProvider.getPortalRequestInfo(isA(HttpServletRequest.class)))
.thenReturn(portalRequestInfo);
}
/**
* {@link CacheControl} says don't cache, make sure no caching.
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doRenderMarkupNoCacheControl()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletData<PortletRenderResult>, PortletRenderResult> cacheState =
new TestingCacheState<
CachedPortletData<PortletRenderResult>, PortletRenderResult>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(false);
cacheControl.setExpirationTime(0);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletRenderState(request, portletWindowId))
.thenReturn(cacheState);
when(portletCacheControlService.shouldOutputBeCached(cacheControl)).thenReturn(false);
when(portletCacheControlService.getCacheSizeThreshold()).thenReturn(102400);
when(portalRequestInfo.getTargetedPortletWindowId()).thenReturn(portletWindowId);
RenderPortletOutputHandler handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
// call 2 times
handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
verify(portletContainer, times(2))
.doRender(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(2))
.getPortletRenderState(request, portletWindowId);
verify(portletCacheControlService, times(2)).getCacheSizeThreshold();
verify(portletCacheControlService, times(2)).shouldOutputBeCached(cacheControl);
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* No cached data exists, but mock a {@link CacheControl} that will trigger the
* portletContainer#doRender, capture the output, and give to the portlet cachecontrol service.
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doRenderMarkupCapture()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
CacheState<CachedPortletData<PortletRenderResult>, PortletRenderResult> cacheState =
new TestingCacheState<
CachedPortletData<PortletRenderResult>, PortletRenderResult>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(false);
cacheControl.setExpirationTime(300);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletRenderState(request, portletWindowId))
.thenReturn(cacheState);
when(portletCacheControlService.shouldOutputBeCached(cacheControl)).thenReturn(true);
when(portalRequestInfo.getTargetedPortletWindowId()).thenReturn(portletWindowId);
RenderPortletOutputHandler handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
verify(portletContainer, times(1))
.doRender(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(1))
.getPortletRenderState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletCacheControlService, times(1)).shouldOutputBeCached(cacheControl);
verify(portletCacheControlService, times(1))
.cachePortletRenderOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
isA(CachedPortletData.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* No cached data exists, but mock a {@link CacheControl} with a negative value for
* expirationtime. Will trigger the portletContainer#doRender, capture the output, and give to
* the portlet cachecontrol service.
*
* <p>negative value for cacheControl expiration time means "cache forever."
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doRenderMarkupCaptureNegativeExpirationTime()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletData<PortletRenderResult>, PortletRenderResult> cacheState =
new TestingCacheState<
CachedPortletData<PortletRenderResult>, PortletRenderResult>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(false);
cacheControl.setExpirationTime(-1);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletRenderState(request, portletWindowId))
.thenReturn(cacheState);
when(portletCacheControlService.shouldOutputBeCached(cacheControl)).thenReturn(true);
when(portalRequestInfo.getTargetedPortletWindowId()).thenReturn(portletWindowId);
RenderPortletOutputHandler handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
verify(portletContainer, times(1))
.doRender(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(1))
.getPortletRenderState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletCacheControlService, times(1)).shouldOutputBeCached(cacheControl);
verify(portletCacheControlService, times(1))
.cachePortletRenderOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
isA(CachedPortletData.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Mimic workflow when cached portlet data using "expiration" method is available.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doRenderMarkupCachedContentExpirationMethodTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletData<PortletRenderResult>, PortletRenderResult> cacheState =
new TestingCacheState<
CachedPortletData<PortletRenderResult>, PortletRenderResult>();
cacheState.setUseCachedData(true);
CacheControl cacheControl = cacheState.getCacheControl();
final PortletRenderResult portletResult = new PortletRenderResult("title", null, 0, 100);
final String output = "<p>Some content</p>";
CachedPortletData<PortletRenderResult> cachedPortletData =
new CachedPortletData<PortletRenderResult>(
portletResult,
output,
null,
null,
false,
null,
cacheControl.getExpirationTime());
cacheState.setCachedPortletData(cachedPortletData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletRenderState(request, portletWindowId))
.thenReturn(cacheState);
when(portalRequestInfo.getTargetedPortletWindowId()).thenReturn(portletWindowId);
RenderPortletOutputHandler handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
Assert.assertEquals(output, handler.getOutput());
verify(portletCacheControlService, times(1))
.getPortletRenderState(request, portletWindowId);
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Mimic workflow when data cached portlet data using "validation" method is available.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doRenderMarkupCachedContentValidationNotExpiredMethodTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletData<PortletRenderResult>, PortletRenderResult> cacheState =
new TestingCacheState<
CachedPortletData<PortletRenderResult>, PortletRenderResult>();
cacheState.setUseCachedData(true);
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setETag("123456");
cacheControl.setExpirationTime(300);
final PortletRenderResult portletResult = new PortletRenderResult("title", null, 0, 100);
final String output = "<p>Some content</p>";
CachedPortletData<PortletRenderResult> cachedPortletData =
new CachedPortletData<PortletRenderResult>(
portletResult,
output,
null,
null,
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
cacheState.setCachedPortletData(cachedPortletData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletRenderState(request, portletWindowId))
.thenReturn(cacheState);
when(portalRequestInfo.getTargetedPortletWindowId()).thenReturn(portletWindowId);
RenderPortletOutputHandler handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
Assert.assertEquals(output, handler.getOutput());
verify(portletCacheControlService, times(1))
.getPortletRenderState(request, portletWindowId);
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Mimic workflow when data cached portlet data using "validation" method is available.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doRenderMarkupCachedContentValidationMethodExpiredTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletData<PortletRenderResult>, PortletRenderResult> cacheState =
new TestingCacheState<
CachedPortletData<PortletRenderResult>, PortletRenderResult>();
CacheControl cacheControl = cacheState.getCacheControl();
// by setting useCachedContent to true, we are saying even though content is expired, replay it anyways (since etag is still valid)
cacheControl.setUseCachedContent(true);
cacheControl.setETag("123456");
cacheControl.setExpirationTime(300);
final PortletRenderResult portletResult = new PortletRenderResult("title", null, 0, 100);
final String output = "<p>Some content</p>";
CachedPortletData<PortletRenderResult> cachedPortletData =
new CachedPortletData<PortletRenderResult>(
portletResult, output, null, null, false, cacheControl.getETag(), 1);
cacheState.setCachedPortletData(cachedPortletData);
final long expTime = cachedPortletData.getExpirationTime();
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletRenderState(request, portletWindowId))
.thenReturn(cacheState);
when(portalRequestInfo.getTargetedPortletWindowId()).thenReturn(portletWindowId);
RenderPortletOutputHandler handler = new RenderPortletOutputHandler("UTF-8");
portletRenderer.doRenderMarkup(portletWindowId, request, response, handler);
Assert.assertEquals(output, handler.getOutput());
// verify the expiration time has been updated
Assert.assertNotSame(expTime, cachedPortletData.getTimeStored());
verify(portletCacheControlService, times(1))
.getPortletRenderState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doRender(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(1))
.cachePortletRenderOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
isA(CachedPortletData.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Verify invoking portletRenderer#doAction removes cached content.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doActionPurgesCachedContent()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
setupPortletExecutionMocks(request);
// doAction will trigger purge
portletRenderer.doAction(portletWindowId, request, response);
verify(portletCacheControlService, times(1))
.purgeCachedPortletData(portletWindowId, request);
verify(portletContainer, times(1))
.doAction(
isA(PortletWindow.class),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletHttpServletResponseWrapper.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* {@link CacheControl} says don't cache, make sure no caching for doServeResource.
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@SuppressWarnings("unchecked")
@Test
public void testDoServeResourceNoCache()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(false);
cacheControl.setExpirationTime(0);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
when(portletCacheControlService.shouldOutputBeCached(cacheControl)).thenReturn(false);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
// call 2 times
portletRenderer.doServeResource(portletWindowId, request, response, handler);
verify(portletCacheControlService, times(2)).getCacheSizeThreshold();
verify(portletCacheControlService, times(2))
.getPortletResourceState(request, portletWindowId);
verify(portletContainer, times(2))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(2)).shouldOutputBeCached(isA(CacheControl.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* No cached data exists, but mock a {@link CacheControl} that will trigger the
* portletContainer#doServeResource, capture the output, and give to the portlet cachecontrol
* service.
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doServeResourceCapture()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
response.setContentType("application/octet-stream");
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(false);
cacheControl.setExpirationTime(300);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
when(portletCacheControlService.shouldOutputBeCached(cacheControl)).thenReturn(true);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(1)).shouldOutputBeCached(isA(CacheControl.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* No cached data exists, but mock a {@link CacheControl} with a negative value for
* expirationtime. Will trigger the portletContainer#doServeResource, capture the output, and
* give to the portlet cachecontrol service.
*
* <p>negative value for cacheControl expiration time means "cache forever."
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doServeResourceMarkupCaptureNegativeExpirationTime()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
response.setContentType("application/octet-stream");
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(false);
cacheControl.setExpirationTime(-1);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
when(portletCacheControlService.shouldOutputBeCached(cacheControl)).thenReturn(true);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService, times(1)).shouldOutputBeCached(isA(CacheControl.class));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Mimic workflow when cached portlet data using "expiration" method is available.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doServeResourceCachedContentExpirationMethodTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
final String output = "{ \"hello\": \"world\" }";
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, Collections.EMPTY_MAP, null, null, null, null);
final long expirationTime = System.currentTimeMillis() - 60000;
cachedPortletData.updateExpirationTime(50000);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService)
.cachePortletResourceOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
eq(cachedPortletResourceData));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Mimic workflow when cached portlet data using "validation" method is available.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doServeResourceCachedContentValidationMethodTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
cacheControl.setETag("123456");
final String output = "{ \"hello\": \"world\" }";
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, Collections.EMPTY_MAP, null, null, null, null);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
byte[] fromResponse = response.getContentAsByteArray();
assertArrayEquals(output.getBytes(), fromResponse);
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService)
.cachePortletResourceOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
eq(cachedPortletResourceData));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Same as {@link #doServeResourceCachedContentValidationMethodTest()}, but simulate browser
* sending If-None-Match header that matches the etag. Verify no content returned and a 304
* status code.
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doServeResourceUseBrowserContentTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("If-None-Match", "123456");
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
cacheState.setUseBrowserData(true);
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
cacheControl.setETag("123456");
final String output = "{ \"hello\": \"world\" }";
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, Collections.EMPTY_MAP, null, null, null, null);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
//byte [] fromResponse = response.getContentAsByteArray();
Assert.assertEquals(0, response.getContentLength());
Assert.assertEquals(304, response.getStatus());
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
@Test
public void doServeResourceCachedContentValidationMethodNotModifiedTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("If-None-Match", "123456");
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
cacheState.setBrowserSetEtag(true);
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
cacheControl.setETag("123456");
final String output = "{ \"hello\": \"world\" }";
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, Collections.EMPTY_MAP, null, null, null, null);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
//byte [] fromResponse = response.getContentAsByteArray();
Assert.assertEquals(0, response.getContentLength());
Assert.assertEquals(304, response.getStatus());
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService)
.cachePortletResourceOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
eq(cachedPortletResourceData));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Same as {@link #doServeResourceCachedContentValidationMethodTest()}, but simulate browser
* sending If-None-Match header with mismatched etag. Response is 200 with content and new etag
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doServeResourceCachedContentValidationMethodIfNoneMatchInvalidTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("If-None-Match", "123456");
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
cacheState.setUseCachedData(true);
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
cacheControl.setETag("123457");
final String output = "{ \"hello\": \"world\" }";
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, Collections.EMPTY_MAP, null, null, null, null);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
byte[] fromResponse = response.getContentAsByteArray();
assertArrayEquals(output.getBytes(), fromResponse);
Assert.assertEquals(200, response.getStatus());
Assert.assertEquals("123457", response.getHeader("ETag"));
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Same as {@link #doServeResourceCachedContentValidationMethodNotModifiedTest()}, however the
* CachedPortletData is older than it's expiration time. Verify the renderer still detects the
* etag and returns 304 not modified.
*
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
@Test
public void doServeResourceCachedContentValidationMethodNotModifiedInternalCacheExpiredTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("If-None-Match", "123456");
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
cacheState.setBrowserSetEtag(true);
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
cacheControl.setETag("123456");
final String output = "{ \"hello\": \"world\" }";
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, Collections.EMPTY_MAP, null, null, null, null);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
Assert.assertEquals(0, response.getContentLength());
Assert.assertEquals(304, response.getStatus());
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verify(portletCacheControlService, times(1)).getCacheSizeThreshold();
verify(portletContainer, times(1))
.doServeResource(
eq(plutoPortletWindow),
isA(PortletHttpServletRequestWrapper.class),
isA(PortletResourceHttpServletResponseWrapper.class));
verify(portletCacheControlService)
.cachePortletResourceOutput(
eq(portletWindowId),
isA(PortletHttpServletRequestWrapper.class),
eq(cacheState),
eq(cachedPortletResourceData));
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
/**
* Verify headers stored in cache are replayed on the response for cached doServeResource
* content.
*
* @throws PortletContainerException
* @throws IOException
* @throws PortletException
*/
@Test
public void doServeResourceCachedContentReplayHeadersTest()
throws PortletException, IOException, PortletContainerException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
TestingCacheState<CachedPortletResourceData<Long>, Long> cacheState =
new TestingCacheState<CachedPortletResourceData<Long>, Long>();
cacheState.setUseCachedData(true);
CacheControl cacheControl = cacheState.getCacheControl();
cacheControl.setUseCachedContent(true);
cacheControl.setExpirationTime(300);
final String output = "{ \"hello\": \"world\" }";
final Map<String, List<Serializable>> headers =
ImmutableMap.<String, List<Serializable>>of(
"header1", Arrays.<Serializable>asList("value1"),
"header2", Arrays.<Serializable>asList("value2", "value3"));
final CachedPortletData<Long> cachedPortletData =
new CachedPortletData<Long>(
1000l,
output,
null,
"application/json",
false,
cacheControl.getETag(),
cacheControl.getExpirationTime());
final CachedPortletResourceData<Long> cachedPortletResourceData =
new CachedPortletResourceData<Long>(
cachedPortletData, headers, null, null, null, null);
cacheState.setCachedPortletData(cachedPortletResourceData);
setupPortletExecutionMocks(request);
when(portletCacheControlService.getPortletResourceState(request, portletWindowId))
.thenReturn(cacheState);
ResourcePortletOutputHandler handler = new ResourcePortletOutputHandler(response);
portletRenderer.doServeResource(portletWindowId, request, response, handler);
byte[] fromResponse = response.getContentAsByteArray();
assertArrayEquals(output.getBytes(), fromResponse);
Assert.assertEquals("value1", response.getHeader("header1"));
Assert.assertEquals(
Arrays.asList(new String[] {"value2", "value3"}), response.getHeaders("header2"));
verify(portletCacheControlService, times(1))
.getPortletResourceState(request, portletWindowId);
verifyNoMoreInteractions(portletContainer, portletCacheControlService);
}
}