/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.resiliency.spi.agent; import com.liferay.portal.kernel.model.Layout; import com.liferay.portal.kernel.model.Portlet; import com.liferay.portal.kernel.resiliency.PortalResiliencyException; import com.liferay.portal.kernel.servlet.BufferCacheServletResponse; import com.liferay.portal.kernel.servlet.MetaInfoCacheServletResponse; import com.liferay.portal.kernel.servlet.StubHttpServletResponse; import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor; import com.liferay.portal.kernel.util.KeyValuePair; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.ThreadLocalDistributor; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.model.impl.LayoutImpl; import com.liferay.portal.model.impl.PortletImpl; import com.liferay.portal.util.PortalImpl; import com.liferay.portal.util.PropsImpl; import com.liferay.registry.BasicRegistryImpl; import com.liferay.registry.RegistryUtil; import java.io.IOException; import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; /** * @author Shuyang Zhou */ public class SPIAgentResponseTest { @ClassRule public static final CodeCoverageAssertor codeCoverageAssertor = CodeCoverageAssertor.INSTANCE; @BeforeClass public static void setUpClass() throws Exception { RegistryUtil.setRegistry(new BasicRegistryImpl()); PortalUtil portalUtil = new PortalUtil(); portalUtil.setPortal(new PortalImpl()); PropsUtil.setProps(new PropsImpl()); ThreadLocalDistributor threadLocalDistributor = new ThreadLocalDistributor(); threadLocalDistributor.setThreadLocalSources( Arrays.asList( new KeyValuePair( SPIAgentResponseTest.class.getName(), "_threadLocal"))); threadLocalDistributor.afterPropertiesSet(); } @Before public void setUp() throws IOException { MockHttpServletRequest originalRequest = new MockHttpServletRequest(); Portlet portlet = new PortletImpl() { @Override public String getContextName() { return _SERVLET_CONTEXT_NAME; } }; originalRequest.setAttribute(WebKeys.SPI_AGENT_PORTLET, portlet); HttpSession session = originalRequest.getSession(); session.setAttribute(_SESSION_ATTRIBUTE_1, _SESSION_ATTRIBUTE_1); session.setAttribute(_SESSION_ATTRIBUTE_2, _SESSION_ATTRIBUTE_2); _mockHttpServletRequest = new MockHttpServletRequest(); _mockHttpServletRequest.setAttribute( WebKeys.SPI_AGENT_PORTLET, portlet); _mockHttpServletRequest.setAttribute( WebKeys.SPI_AGENT_REQUEST, new SPIAgentRequest(originalRequest)); RequestAttributes.setRequestAttributes(_mockHttpServletRequest); } @Test public void testCaptureRequestSessionAttributes() { SPIAgentResponse spiAgentResponse = new SPIAgentResponse( _SERVLET_CONTEXT_NAME); String threadLocalValue = "threadLocalValue"; _threadLocal.set(threadLocalValue); HttpSession session = _mockHttpServletRequest.getSession(); session.setAttribute(_SESSION_ATTRIBUTE_1, _SESSION_ATTRIBUTE_1); session.setAttribute(_SESSION_ATTRIBUTE_2, null); session.setAttribute(_SESSION_ATTRIBUTE_3, _SESSION_ATTRIBUTE_3); spiAgentResponse.captureRequestSessionAttributes( _mockHttpServletRequest); _threadLocal.remove(); Map<String, Serializable> distributedRequestAttributes = spiAgentResponse.distributedRequestAttributes; Assert.assertEquals( distributedRequestAttributes.toString(), 2, distributedRequestAttributes.size()); Assert.assertEquals( RequestAttributes.ATTRIBUTE_1, distributedRequestAttributes.get(RequestAttributes.ATTRIBUTE_1)); Assert.assertEquals( RequestAttributes.ATTRIBUTE_3, distributedRequestAttributes.get(RequestAttributes.ATTRIBUTE_3)); Map<String, Serializable> deltaSessionAttributes = spiAgentResponse.deltaSessionAttributes; Assert.assertEquals( deltaSessionAttributes.toString(), 3, deltaSessionAttributes.size()); Assert.assertEquals( _SESSION_ATTRIBUTE_1, deltaSessionAttributes.get(_SESSION_ATTRIBUTE_1)); Assert.assertNull(deltaSessionAttributes.get(_SESSION_ATTRIBUTE_2)); Assert.assertEquals( _SESSION_ATTRIBUTE_3, deltaSessionAttributes.get(_SESSION_ATTRIBUTE_3)); spiAgentResponse.restoreThreadLocals(); Assert.assertEquals(threadLocalValue, _threadLocal.get()); _threadLocal.remove(); } @Test public void testCaptureResponse() throws IOException { // Not a portal resiliency action SPIAgentResponse spiAgentResponse = new SPIAgentResponse( _SERVLET_CONTEXT_NAME); spiAgentResponse.captureResponse( new MockHttpServletRequest(), new BufferCacheServletResponse(new MockHttpServletResponse())); Assert.assertFalse(spiAgentResponse.portalResiliencyResponse); Assert.assertNull(spiAgentResponse.metaData); Assert.assertNull(spiAgentResponse.byteData); Assert.assertNull(spiAgentResponse.stringData); // Portal resiliency action, byte model output, empty MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest(); mockHttpServletRequest.setAttribute( WebKeys.PORTAL_RESILIENCY_ACTION, Boolean.TRUE); BufferCacheServletResponse bufferCacheServletResponse = new BufferCacheServletResponse(new MockHttpServletResponse()); bufferCacheServletResponse.setByteBuffer(ByteBuffer.allocate(0)); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertNull(spiAgentResponse.byteData); Assert.assertNull(spiAgentResponse.stringData); // Portal resiliency action, byte model output, native buffer byte[] byteArray = new byte[] {(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5}; ByteBuffer byteBuffer = ByteBuffer.allocateDirect(byteArray.length); byteBuffer.put(byteArray); byteBuffer.clear(); bufferCacheServletResponse.setByteBuffer(byteBuffer); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertArrayEquals(byteArray, spiAgentResponse.byteData); Assert.assertNull(spiAgentResponse.stringData); // Portal resiliency action, byte model output, whole buffer bufferCacheServletResponse.setByteBuffer(ByteBuffer.wrap(byteArray)); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertSame(byteArray, spiAgentResponse.byteData); Assert.assertNull(spiAgentResponse.stringData); // Portal resiliency action, byte model output, partial buffer bufferCacheServletResponse.setByteBuffer( ByteBuffer.wrap(byteArray, 2, 2)); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertArrayEquals( new byte[] {(byte)2, (byte)3}, spiAgentResponse.byteData); Assert.assertNull(spiAgentResponse.stringData); // Portal resiliency action, char model output, empty bufferCacheServletResponse.setString(StringPool.BLANK); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertNull(spiAgentResponse.byteData); Assert.assertNull(spiAgentResponse.stringData); // Portal resiliency action, char model output, without footer String content = "content"; bufferCacheServletResponse.setString(content); mockHttpServletRequest.setParameter( "portalResiliencyPortletShowFooter", StringPool.FALSE); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertNull(spiAgentResponse.byteData); Assert.assertSame(content, spiAgentResponse.stringData); // Portal resiliency action, char model output, not HTML, without footer bufferCacheServletResponse.setString(content); mockHttpServletRequest.setParameter( "portalResiliencyPortletShowFooter", StringPool.TRUE); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertNull(spiAgentResponse.byteData); Assert.assertSame(content, spiAgentResponse.stringData); // Portal resiliency action, char model output, with footer content = "<div>content</div>"; bufferCacheServletResponse.setString(content); mockHttpServletRequest.setLocalAddr("127.0.0.1"); mockHttpServletRequest.setLocalPort(1234); PortalUtil.setPortalInetSocketAddresses(mockHttpServletRequest); mockHttpServletRequest.setParameter( "portalResiliencyPortletShowFooter", StringPool.TRUE); spiAgentResponse.captureResponse( mockHttpServletRequest, bufferCacheServletResponse); Assert.assertTrue(spiAgentResponse.portalResiliencyResponse); Assert.assertNotNull(spiAgentResponse.metaData); Assert.assertNull(spiAgentResponse.byteData); Assert.assertEquals( "<div>content<div class=\"alert alert-info\"><strong>This " + "portlet is from SPI 1234</strong></div></div>", spiAgentResponse.stringData); } @Test public void testPopulate() throws IOException, PortalResiliencyException { // Exception SPIAgentResponse spiAgentResponse = new SPIAgentResponse( _SERVLET_CONTEXT_NAME); Exception exception = new Exception(); spiAgentResponse.setException(exception); try { spiAgentResponse.populate( new MockHttpServletRequest(), new MockHttpServletResponse()); Assert.fail(); } catch (PortalResiliencyException pre) { Assert.assertEquals("SPI exception", pre.getMessage()); Assert.assertSame(exception, pre.getCause()); } // Not a portal resiliency response spiAgentResponse.setException(null); spiAgentResponse.populate( new MockHttpServletRequest(), new MockHttpServletResponse()); // Distributed request attributes, without type setting spiAgentResponse.portalResiliencyResponse = true; Map<String, Serializable> distributedRequestAttributes = new HashMap<>(); distributedRequestAttributes.put( RequestAttributes.ATTRIBUTE_1, RequestAttributes.ATTRIBUTE_1); distributedRequestAttributes.put( RequestAttributes.ATTRIBUTE_3, RequestAttributes.ATTRIBUTE_3); spiAgentResponse.distributedRequestAttributes = distributedRequestAttributes; Map<String, Serializable> deltaSessionAttributes = new HashMap<>(); deltaSessionAttributes.put(_SESSION_ATTRIBUTE_1, _SESSION_ATTRIBUTE_1); deltaSessionAttributes.put(_SESSION_ATTRIBUTE_2, _SESSION_ATTRIBUTE_2); spiAgentResponse.deltaSessionAttributes = deltaSessionAttributes; MetaInfoCacheServletResponse metaInfoCacheServletResponse = new MetaInfoCacheServletResponse(new MockHttpServletResponse()); spiAgentResponse.metaData = metaInfoCacheServletResponse.getMetaData(); spiAgentResponse.threadLocalDistributors = new ThreadLocalDistributor[0]; MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest(); spiAgentResponse.populate( mockHttpServletRequest, new MockHttpServletResponse()); Enumeration<String> requestAttributeNameEnumeration = mockHttpServletRequest.getAttributeNames(); List<String> requestAttributeNames = ListUtil.fromEnumeration( requestAttributeNameEnumeration); Assert.assertEquals( requestAttributeNames.toString(), 2, requestAttributeNames.size()); Assert.assertTrue( requestAttributeNames.contains(RequestAttributes.ATTRIBUTE_1)); Assert.assertTrue( requestAttributeNames.contains(RequestAttributes.ATTRIBUTE_3)); Assert.assertEquals( RequestAttributes.ATTRIBUTE_1, mockHttpServletRequest.getAttribute(RequestAttributes.ATTRIBUTE_1)); Assert.assertEquals( RequestAttributes.ATTRIBUTE_1, mockHttpServletRequest.getAttribute(RequestAttributes.ATTRIBUTE_1)); // Distributed request attributes, with type setting distributedRequestAttributes.clear(); String typeSetting = "typeSetting"; distributedRequestAttributes.put( WebKeys.SPI_AGENT_LAYOUT_TYPE_SETTINGS, typeSetting); mockHttpServletRequest.setAttribute(WebKeys.LAYOUT, new LayoutImpl()); spiAgentResponse.populate( mockHttpServletRequest, new MockHttpServletResponse()); Layout layout = (Layout)mockHttpServletRequest.getAttribute( WebKeys.LAYOUT); Assert.assertEquals(typeSetting, layout.getTypeSettings()); // Successfully output byte data byte[] outputData = new byte[10]; spiAgentResponse.byteData = outputData; BufferCacheServletResponse bufferCacheServletResponse = new BufferCacheServletResponse(new MockHttpServletResponse()); spiAgentResponse.populate( mockHttpServletRequest, bufferCacheServletResponse); ByteBuffer byteBuffer = bufferCacheServletResponse.getByteBuffer(); Assert.assertSame(outputData, byteBuffer.array()); // Unable to output byte data final IOException ioException = new IOException(); HttpServletResponse httpServletResponse = new StubHttpServletResponse() { @Override public void flushBuffer() throws IOException { throw ioException; } @Override public boolean isCommitted() { return false; } @Override public void reset() { } @Override public void setContentLength(int contentLength) { } }; try { spiAgentResponse.populate( mockHttpServletRequest, httpServletResponse); Assert.fail(); } catch (PortalResiliencyException pre) { Assert.assertSame(ioException, pre.getCause()); } // Successfully output string data String stringData = "stringData"; spiAgentResponse.stringData = stringData; bufferCacheServletResponse = new BufferCacheServletResponse( new MockHttpServletResponse()); spiAgentResponse.populate( mockHttpServletRequest, bufferCacheServletResponse); CharBuffer charBuffer = bufferCacheServletResponse.getCharBuffer(); Assert.assertEquals(stringData, charBuffer.toString()); // Unable to output string data try { spiAgentResponse.populate( mockHttpServletRequest, httpServletResponse); Assert.fail(); } catch (PortalResiliencyException pre) { Assert.assertSame(ioException, pre.getCause()); } } private static final String _SERVLET_CONTEXT_NAME = "SERVLET_CONTEXT_NAME"; private static final String _SESSION_ATTRIBUTE_1 = "SESSION_ATTRIBUTE_1"; private static final String _SESSION_ATTRIBUTE_2 = "SESSION_ATTRIBUTE_2"; private static final String _SESSION_ATTRIBUTE_3 = "SESSION_ATTRIBUTE_3"; private static final ThreadLocal<String> _threadLocal = new ThreadLocal<>(); private MockHttpServletRequest _mockHttpServletRequest; }