/**
* 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.io.BigEndianCodec;
import com.liferay.portal.kernel.io.Serializer;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.nio.intraband.Datagram;
import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
import com.liferay.portal.kernel.nio.intraband.mailbox.MailboxException;
import com.liferay.portal.kernel.nio.intraband.mailbox.MailboxUtil;
import com.liferay.portal.kernel.nio.intraband.test.MockIntraband;
import com.liferay.portal.kernel.nio.intraband.test.MockRegistrationReference;
import com.liferay.portal.kernel.resiliency.PortalResiliencyException;
import com.liferay.portal.kernel.resiliency.spi.MockSPI;
import com.liferay.portal.kernel.resiliency.spi.SPI;
import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
import com.liferay.portal.kernel.resiliency.spi.agent.AcceptorServlet;
import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
import com.liferay.portal.kernel.servlet.ReadOnlyServletResponse;
import com.liferay.portal.kernel.test.CaptureHandler;
import com.liferay.portal.kernel.test.JDKLoggerTestUtil;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.AggregateTestRule;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.rule.NewEnv;
import com.liferay.portal.kernel.util.InetAddressUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.kernel.util.PropsUtilAdvice;
import com.liferay.portal.kernel.util.SocketUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.model.impl.PortletImpl;
import com.liferay.portal.test.rule.AdviseWith;
import com.liferay.portal.test.rule.AspectJNewEnvTestRule;
import com.liferay.portal.util.PropsImpl;
import com.liferay.portal.util.PropsValues;
import com.liferay.registry.BasicRegistryImpl;
import com.liferay.registry.RegistryUtil;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketImpl;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* @author Shuyang Zhou
*/
public class HttpClientSPIAgentTest {
@ClassRule
@Rule
public static final AggregateTestRule aggregateTestRule =
new AggregateTestRule(
CodeCoverageAssertor.INSTANCE, AspectJNewEnvTestRule.INSTANCE);
@Before
public void setUp() {
RegistryUtil.setRegistry(new BasicRegistryImpl());
PropsUtil.setProps(new PropsImpl());
_portlet = new PortletImpl() {
@Override
public String getContextName() {
return _SERVLET_CONTEXT_NAME;
}
};
_mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_PORTLET, _portlet);
}
@Test
public void testBorrowSocket() throws Exception {
// Create on empty
ServerSocketChannel serverSocketChannel =
SocketUtil.createServerSocketChannel(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort(), null);
serverSocketChannel.configureBlocking(true);
try (ServerSocket serverSocket = serverSocketChannel.socket()) {
SPIConfiguration spiConfiguration = new SPIConfiguration(
null, null, serverSocket.getLocalPort(),
_spiConfiguration.getBaseDir(), null, null, null);
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
Socket socket = httpClientSPIAgent.borrowSocket();
closePeers(socket, serverSocket);
// Clean up when closed
Queue<Socket> socketBlockingQueue =
httpClientSPIAgent.socketBlockingQueue;
socketBlockingQueue.add(socket);
socket = httpClientSPIAgent.borrowSocket();
closePeers(socket, serverSocket);
// Clean up not connected
socketBlockingQueue.add(new Socket());
socket = httpClientSPIAgent.borrowSocket();
closePeers(socket, serverSocket);
// Clean up when input is shutdown
socket = httpClientSPIAgent.borrowSocket();
socket.shutdownInput();
socketBlockingQueue.add(socket);
socket = httpClientSPIAgent.borrowSocket();
closePeers(socket, serverSocket);
socket = serverSocket.accept();
socket.close();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
HttpClientSPIAgent.class.getName(), Level.OFF)) {
// Clean up when input is shutdown, failed without log
List<LogRecord> logRecords = captureHandler.getLogRecords();
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
socket.shutdownInput();
SocketImpl socketImpl = swapSocketImpl(socket, null);
socketBlockingQueue.add(socket);
socket = httpClientSPIAgent.borrowSocket();
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
socket = serverSocket.accept();
socket.close();
Assert.assertTrue(logRecords.isEmpty());
// Clean up when input is shutdown, failed with log
logRecords = captureHandler.resetLogLevel(Level.WARNING);
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
socket.shutdownInput();
socketImpl = swapSocketImpl(socket, null);
socketBlockingQueue.add(socket);
socket = httpClientSPIAgent.borrowSocket();
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
socket = serverSocket.accept();
socket.close();
Assert.assertEquals(
logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Throwable throwable = logRecord.getThrown();
Assert.assertSame(IOException.class, throwable.getClass());
}
// Clean up when output is shutdown()
socket = httpClientSPIAgent.borrowSocket();
socket.shutdownOutput();
socketBlockingQueue.add(socket);
socket = httpClientSPIAgent.borrowSocket();
closePeers(socket, serverSocket);
socket = serverSocket.accept();
socket.close();
// Reuse socket
socket = httpClientSPIAgent.borrowSocket();
socketBlockingQueue.add(socket);
Assert.assertSame(socket, httpClientSPIAgent.borrowSocket());
closePeers(socket, serverSocket);
}
}
@Test
public void testConstructor() throws Exception {
MockRegistrationReference mockRegistrationReference =
new MockRegistrationReference(new MockIntraband());
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration, mockRegistrationReference);
Assert.assertSame(
mockRegistrationReference,
httpClientSPIAgent.registrationReference);
Assert.assertEquals(
new InetSocketAddress(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort()),
httpClientSPIAgent.socketAddress);
BlockingQueue<Socket> socketBlockingQueue =
httpClientSPIAgent.socketBlockingQueue;
Assert.assertTrue(socketBlockingQueue.isEmpty());
Assert.assertEquals(
PropsValues.PORTAL_RESILIENCY_SPI_AGENT_CLIENT_POOL_MAX_SIZE,
socketBlockingQueue.remainingCapacity());
StringBundler sb = new StringBundler();
sb.append("POST ");
sb.append(HttpClientSPIAgent.SPI_AGENT_CONTEXT_PATH);
sb.append(HttpClientSPIAgent.MAPPING_PATTERN);
sb.append(" HTTP/1.1\r\nHost: localhost:");
sb.append(_spiConfiguration.getConnectorPort());
sb.append("\r\nContent-Length: 8\r\n\r\n");
String httpServletRequestContentString = sb.toString();
Assert.assertArrayEquals(
httpServletRequestContentString.getBytes("US-ASCII"),
httpClientSPIAgent.httpServletRequestContent);
}
@Test
public void testConsumeHttpResponseHead() throws Exception {
// Wrong status line
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
String wrongStatusLine = "Wrong status line";
try {
httpClientSPIAgent.consumeHttpResponseHead(
new DataInputStream(
new UnsyncByteArrayInputStream(
wrongStatusLine.getBytes("US-ASCII"))));
Assert.fail();
}
catch (IOException ioe) {
Assert.assertEquals(
"Error status line: " + wrongStatusLine, ioe.getMessage());
}
// Wrong ending
String responseContentWrongEnding = "HTTP/1.1 200 OK\n";
Assert.assertFalse(
httpClientSPIAgent.consumeHttpResponseHead(
new DataInputStream(
new UnsyncByteArrayInputStream(
responseContentWrongEnding.getBytes("US-ASCII")))));
// Keep alive
String responseContentKeepAlive = "HTTP/1.1 200 OK\n\n";
Assert.assertFalse(
httpClientSPIAgent.consumeHttpResponseHead(
new DataInputStream(
new UnsyncByteArrayInputStream(
responseContentKeepAlive.getBytes("US-ASCII")))));
// Wrong close
String responseContentWrongClose =
"HTTP/1.1 200 OK\nconnection:wrong\n\n";
Assert.assertFalse(
httpClientSPIAgent.consumeHttpResponseHead(
new DataInputStream(
new UnsyncByteArrayInputStream(
responseContentWrongClose.getBytes("US-ASCII")))));
// Correct close
String responseContentCorrectClose =
"HTTP/1.1 200 OK\nkey:value\nconnection:close\n\n";
Assert.assertTrue(
httpClientSPIAgent.consumeHttpResponseHead(
new DataInputStream(
new UnsyncByteArrayInputStream(
responseContentCorrectClose.getBytes("US-ASCII")))));
}
@Test
public void testDestroy() throws Exception {
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
HttpClientSPIAgent.class.getName(), Level.OFF)) {
// Error without log
List<LogRecord> logRecords = captureHandler.getLogRecords();
ServerSocketChannel serverSocketChannel =
SocketUtil.createServerSocketChannel(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort(), null);
serverSocketChannel.configureBlocking(true);
try (ServerSocket serverSocket = serverSocketChannel.socket()) {
Socket socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
SocketImpl socketImpl = swapSocketImpl(socket, null);
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
Queue<Socket> socketBlockingQueue =
httpClientSPIAgent.socketBlockingQueue;
socketBlockingQueue.add(socket);
httpClientSPIAgent.destroy();
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
Assert.assertTrue(logRecords.isEmpty());
// Error with log
logRecords = captureHandler.resetLogLevel(Level.WARNING);
httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
socketBlockingQueue = httpClientSPIAgent.socketBlockingQueue;
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
socketImpl = swapSocketImpl(socket, null);
socketBlockingQueue.add(socket);
httpClientSPIAgent.destroy();
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
Assert.assertEquals(
logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Throwable throwable = logRecord.getThrown();
Assert.assertSame(IOException.class, throwable.getClass());
// Successfully destroy
logRecords = captureHandler.resetLogLevel(Level.WARNING);
httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
socketBlockingQueue = httpClientSPIAgent.socketBlockingQueue;
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
socketBlockingQueue.add(socket);
httpClientSPIAgent.destroy();
closePeers(socket, serverSocket);
Assert.assertTrue(logRecords.isEmpty());
}
}
}
@Test
public void testInit() throws Exception {
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
final AtomicBoolean throwException = new AtomicBoolean();
SPI spi = new MockSPI() {
@Override
public void addServlet(
String contextPath, String docBasePath, String mappingPattern,
String servletClassName) {
if (throwException.get()) {
throw new RuntimeException();
}
Assert.assertEquals(
HttpClientSPIAgent.SPI_AGENT_CONTEXT_PATH, contextPath);
Assert.assertEquals(
_spiConfiguration.getBaseDir(), docBasePath);
Assert.assertEquals(
HttpClientSPIAgent.MAPPING_PATTERN, mappingPattern);
Assert.assertEquals(
AcceptorServlet.class.getName(), servletClassName);
}
@Override
public SPIConfiguration getSPIConfiguration() {
return _spiConfiguration;
}
};
httpClientSPIAgent.init(spi);
throwException.set(true);
try {
httpClientSPIAgent.init(spi);
Assert.fail();
}
catch (PortalResiliencyException pre) {
Throwable throwable = pre.getCause();
Assert.assertSame(RuntimeException.class, throwable.getClass());
}
}
@AdviseWith(adviceClasses = {PropsUtilAdvice.class})
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testPrepareRequest() throws Exception {
PropsUtilAdvice.setProps(
PropsKeys.INTRABAND_MAILBOX_REAPER_THREAD_ENABLED,
Boolean.FALSE.toString());
PropsUtilAdvice.setProps(
PropsKeys.INTRABAND_MAILBOX_STORAGE_LIFE,
String.valueOf(Long.MAX_VALUE));
Serializer serializer = new Serializer();
serializer.writeString(_SERVLET_CONTEXT_NAME);
serializer.writeObject(new SPIAgentRequest(_mockHttpServletRequest));
long receipt = ReflectionTestUtil.invoke(
MailboxUtil.class, "depositMail", new Class<?>[] {ByteBuffer.class},
serializer.toByteBuffer());
byte[] data = new byte[8];
BigEndianCodec.putLong(data, 0, receipt);
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
MockHttpServletRequest mockHttpServletRequest =
new MockHttpServletRequest();
mockHttpServletRequest.setContent(data);
HttpServletRequest httpServletRequest =
httpClientSPIAgent.prepareRequest(mockHttpServletRequest);
Assert.assertNotNull(
httpServletRequest.getAttribute(WebKeys.SPI_AGENT_REQUEST));
}
@Test
public void testPrepareResponse() throws UnknownHostException {
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
MockHttpServletRequest mockHttpServletRequest =
new MockHttpServletRequest();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_PORTLET, _portlet);
MockHttpServletResponse mockHttpServletResponse =
new MockHttpServletResponse();
HttpServletResponse httpServletResponse =
httpClientSPIAgent.prepareResponse(
mockHttpServletRequest, mockHttpServletResponse);
Assert.assertSame(
mockHttpServletResponse,
mockHttpServletRequest.getAttribute(
WebKeys.SPI_AGENT_ORIGINAL_RESPONSE));
Assert.assertNotNull(
mockHttpServletRequest.getAttribute(WebKeys.SPI_AGENT_RESPONSE));
Assert.assertSame(
BufferCacheServletResponse.class, httpServletResponse.getClass());
BufferCacheServletResponse bufferCacheServletResponse =
(BufferCacheServletResponse)httpServletResponse;
ServletResponse servletResponse =
bufferCacheServletResponse.getResponse();
Assert.assertSame(
ReadOnlyServletResponse.class, servletResponse.getClass());
ReadOnlyServletResponse readOnlyServletResponse =
(ReadOnlyServletResponse)servletResponse;
Assert.assertSame(
mockHttpServletResponse, readOnlyServletResponse.getResponse());
}
@Test
public void testReturnSocket() throws Exception {
// Force close, successfully
ServerSocketChannel serverSocketChannel =
SocketUtil.createServerSocketChannel(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort(), null);
serverSocketChannel.configureBlocking(true);
try (ServerSocket serverSocket = serverSocketChannel.socket()) {
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
new SPIConfiguration(
null, null, serverSocket.getLocalPort(),
_spiConfiguration.getBaseDir(), null, null, null),
new MockRegistrationReference(new MockIntraband()));
SocketChannel socketChannel = SocketChannel.open(
httpClientSPIAgent.socketAddress);
Socket socket = socketChannel.socket();
httpClientSPIAgent.returnSocket(socket, true);
Queue<Socket> socketBlockingQueue =
httpClientSPIAgent.socketBlockingQueue;
Assert.assertTrue(socketBlockingQueue.isEmpty());
closePeers(socket, serverSocket);
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
HttpClientSPIAgent.class.getName(), Level.OFF)) {
// Force close, failed without log
List<LogRecord> logRecords = captureHandler.getLogRecords();
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
SocketImpl socketImpl = swapSocketImpl(socket, null);
httpClientSPIAgent.returnSocket(socket, true);
Assert.assertTrue(socketBlockingQueue.isEmpty());
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
Assert.assertTrue(logRecords.isEmpty());
// Force close, failed with log
logRecords = captureHandler.resetLogLevel(Level.WARNING);
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
socketImpl = swapSocketImpl(socket, null);
httpClientSPIAgent.returnSocket(socket, true);
Assert.assertTrue(socketBlockingQueue.isEmpty());
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
Assert.assertEquals(
logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Throwable throwable = logRecord.getThrown();
Assert.assertSame(IOException.class, throwable.getClass());
}
// socket.isConnected()
httpClientSPIAgent.returnSocket(new Socket(), false);
Assert.assertTrue(socketBlockingQueue.isEmpty());
// socket.isInputShutdown()
socketChannel = SocketChannel.open(
httpClientSPIAgent.socketAddress);
socket = socketChannel.socket();
socket.shutdownInput();
httpClientSPIAgent.returnSocket(socket, false);
Assert.assertTrue(socketBlockingQueue.isEmpty());
closePeers(socket, serverSocket);
// socket.isOutputShutdown()
socketChannel = SocketChannel.open(
httpClientSPIAgent.socketAddress);
socket = socketChannel.socket();
socket.shutdownOutput();
httpClientSPIAgent.returnSocket(socket, false);
Assert.assertTrue(socketBlockingQueue.isEmpty());
closePeers(socket, serverSocket);
// Successfully return
socketChannel = SocketChannel.open(
httpClientSPIAgent.socketAddress);
socket = socketChannel.socket();
httpClientSPIAgent.returnSocket(socket, false);
Assert.assertEquals(1, socketBlockingQueue.size());
Assert.assertSame(socket, socketBlockingQueue.poll());
closePeers(socket, serverSocket);
}
}
@Test
public void testService() throws Exception {
// Unable to borrow a socket
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(new MockIntraband()));
try {
httpClientSPIAgent.service(null, null);
Assert.fail();
}
catch (PortalResiliencyException pre) {
Throwable throwable = pre.getCause();
Assert.assertSame(ConnectException.class, throwable.getClass());
}
// Unable to send, successfully close
MockIntraband mockIntraband = new MockIntraband();
IOException ioException = new IOException();
mockIntraband.setIOException(ioException);
httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration, new MockRegistrationReference(mockIntraband));
ServerSocketChannel serverSocketChannel =
SocketUtil.createServerSocketChannel(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort(), null);
serverSocketChannel.configureBlocking(true);
SocketChannel socketChannel = SocketChannel.open(
httpClientSPIAgent.socketAddress);
Socket socket = socketChannel.socket();
Queue<Socket> socketBlockingQueue =
httpClientSPIAgent.socketBlockingQueue;
socketBlockingQueue.add(socket);
MockHttpServletRequest mockHttpServletRequest =
new MockHttpServletRequest();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_PORTLET, _portlet);
try {
httpClientSPIAgent.service(mockHttpServletRequest, null);
Assert.fail();
}
catch (PortalResiliencyException pre) {
Throwable throwable = pre.getCause();
Assert.assertSame(IOException.class, throwable.getClass());
throwable = throwable.getCause();
Assert.assertSame(MailboxException.class, throwable.getClass());
Assert.assertSame(ioException, throwable.getCause());
}
ServerSocket serverSocket = serverSocketChannel.socket();
closePeers(socket, serverSocket);
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
HttpClientSPIAgent.class.getName(), Level.OFF)) {
// Unable to send, unable to close, without log
List<LogRecord> logRecords = captureHandler.getLogRecords();
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
SocketImpl socketImpl = swapSocketImpl(socket, null);
httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(mockIntraband));
socketBlockingQueue = httpClientSPIAgent.socketBlockingQueue;
socketBlockingQueue.add(socket);
try {
httpClientSPIAgent.service(mockHttpServletRequest, null);
Assert.fail();
}
catch (PortalResiliencyException pre) {
Throwable throwable = pre.getCause();
Assert.assertSame(IOException.class, throwable.getClass());
}
Assert.assertTrue(logRecords.isEmpty());
swapSocketImpl(socket, socketImpl);
closePeers(socket, serverSocket);
// Unable to send, unable to close, with log
logRecords = captureHandler.resetLogLevel(Level.WARNING);
socket = new Socket(
InetAddressUtil.getLoopbackInetAddress(),
_spiConfiguration.getConnectorPort());
socketImpl = swapSocketImpl(socket, null);
httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration,
new MockRegistrationReference(mockIntraband));
socketBlockingQueue = httpClientSPIAgent.socketBlockingQueue;
socketBlockingQueue.add(socket);
try {
httpClientSPIAgent.service(mockHttpServletRequest, null);
Assert.fail();
}
catch (PortalResiliencyException pre) {
Throwable throwable = pre.getCause();
Assert.assertSame(IOException.class, throwable.getClass());
}
Assert.assertEquals(logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Throwable throwable = logRecord.getThrown();
Assert.assertSame(IOException.class, throwable.getClass());
swapSocketImpl(socket, socketImpl);
}
closePeers(socket, serverSocket);
// Successfully send
socketChannel = SocketChannel.open(httpClientSPIAgent.socketAddress);
socketChannel.configureBlocking(true);
mockIntraband = new MockIntraband() {
@Override
protected Datagram processDatagram(Datagram datagram) {
try {
long receipt = ReflectionTestUtil.invoke(
MailboxUtil.class, "depositMail",
new Class<?>[] {ByteBuffer.class},
datagram.getDataByteBuffer());
byte[] receiptData = new byte[8];
BigEndianCodec.putLong(receiptData, 0, receipt);
return Datagram.createResponseDatagram(
datagram, ByteBuffer.wrap(receiptData));
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
};
httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration, new MockRegistrationReference(mockIntraband));
socketBlockingQueue = httpClientSPIAgent.socketBlockingQueue;
socket = socketChannel.socket();
socketBlockingQueue.add(socket);
Serializer serializer = new Serializer();
serializer.writeString(_SERVLET_CONTEXT_NAME);
serializer.writeObject(new SPIAgentResponse(_SERVLET_CONTEXT_NAME));
long receipt = ReflectionTestUtil.invoke(
MailboxUtil.class, "depositMail", new Class<?>[] {ByteBuffer.class},
serializer.toByteBuffer());
Socket remoteSocket = serverSocket.accept();
OutputStream outputStream = remoteSocket.getOutputStream();
outputStream.write("HTTP/1.1 200 OK\n\n".getBytes("US-ASCII"));
byte[] receiptData = new byte[8];
BigEndianCodec.putLong(receiptData, 0, receipt);
outputStream.write(receiptData);
outputStream.flush();
httpClientSPIAgent.service(
mockHttpServletRequest, new MockHttpServletResponse());
socket.close();
remoteSocket.close();
serverSocket.close();
}
@Test
public void testTransferResponse() throws Exception {
// Exception
MockRegistrationReference mockRegistrationReference =
new MockRegistrationReference(new MockIntraband());
HttpClientSPIAgent httpClientSPIAgent = new HttpClientSPIAgent(
_spiConfiguration, mockRegistrationReference);
MockHttpServletRequest mockHttpServletRequest =
new MockHttpServletRequest();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_REQUEST,
new SPIAgentRequest(_mockHttpServletRequest));
RecordSPIAgentResponse recordSPIAgentResponse =
new RecordSPIAgentResponse();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_RESPONSE, recordSPIAgentResponse);
MockHttpServletResponse mockHttpServletResponse =
new MockHttpServletResponse();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_ORIGINAL_RESPONSE, mockHttpServletResponse);
Exception exception = new Exception();
httpClientSPIAgent.transferResponse(
mockHttpServletRequest,
new BufferCacheServletResponse(new MockHttpServletResponse()),
exception);
Assert.assertNull(
mockHttpServletRequest.getAttribute(WebKeys.SPI_AGENT_REQUEST));
Assert.assertNull(
mockHttpServletRequest.getAttribute(WebKeys.SPI_AGENT_RESPONSE));
Assert.assertSame(exception, recordSPIAgentResponse.exception);
Assert.assertNull(
mockHttpServletRequest.getAttribute(
WebKeys.SPI_AGENT_ORIGINAL_RESPONSE));
Assert.assertEquals(8, mockHttpServletResponse.getContentLength());
Assert.assertNull(recordSPIAgentResponse._request);
Assert.assertNull(recordSPIAgentResponse._bufferCacheServletResponse);
Assert.assertSame(
mockRegistrationReference,
recordSPIAgentResponse._registrationReference);
Assert.assertSame(
mockHttpServletResponse.getOutputStream(),
recordSPIAgentResponse._outputStream);
// Response
SPIAgentRequest spiAgentRequest = new SPIAgentRequest(
_mockHttpServletRequest);
File tempFile = File.createTempFile(
HttpClientSPIAgentTest.class.getName(), null);
Assert.assertTrue(tempFile.exists());
spiAgentRequest.requestBodyFile = tempFile;
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_REQUEST, spiAgentRequest);
recordSPIAgentResponse = new RecordSPIAgentResponse();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_RESPONSE, recordSPIAgentResponse);
mockHttpServletResponse = new MockHttpServletResponse();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_ORIGINAL_RESPONSE, mockHttpServletResponse);
BufferCacheServletResponse bufferCacheServletResponse =
new BufferCacheServletResponse(new MockHttpServletResponse());
httpClientSPIAgent.transferResponse(
mockHttpServletRequest, bufferCacheServletResponse, null);
Assert.assertFalse(tempFile.exists());
Assert.assertNull(
mockHttpServletRequest.getAttribute(WebKeys.SPI_AGENT_REQUEST));
Assert.assertNull(
mockHttpServletRequest.getAttribute(WebKeys.SPI_AGENT_RESPONSE));
Assert.assertNull(recordSPIAgentResponse.exception);
Assert.assertNull(
mockHttpServletRequest.getAttribute(
WebKeys.SPI_AGENT_ORIGINAL_RESPONSE));
Assert.assertEquals(8, mockHttpServletResponse.getContentLength());
Assert.assertSame(
mockHttpServletRequest, recordSPIAgentResponse._request);
Assert.assertSame(
bufferCacheServletResponse,
recordSPIAgentResponse._bufferCacheServletResponse);
Assert.assertSame(
mockRegistrationReference,
recordSPIAgentResponse._registrationReference);
Assert.assertSame(
mockHttpServletResponse.getOutputStream(),
recordSPIAgentResponse._outputStream);
// Undeletable request body file
spiAgentRequest = new SPIAgentRequest(_mockHttpServletRequest);
tempFile = File.createTempFile(
HttpClientSPIAgentTest.class.getName(), null);
Assert.assertTrue(tempFile.exists());
spiAgentRequest.requestBodyFile = tempFile;
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_REQUEST, spiAgentRequest);
recordSPIAgentResponse = new RecordSPIAgentResponse();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_RESPONSE, recordSPIAgentResponse);
mockHttpServletResponse = new MockHttpServletResponse();
mockHttpServletRequest.setAttribute(
WebKeys.SPI_AGENT_ORIGINAL_RESPONSE, mockHttpServletResponse);
bufferCacheServletResponse = new BufferCacheServletResponse(
new MockHttpServletResponse());
Assert.assertTrue(tempFile.delete());
httpClientSPIAgent.transferResponse(
mockHttpServletRequest, bufferCacheServletResponse, null);
Set<String> files = ReflectionTestUtil.getFieldValue(
Class.forName("java.io.DeleteOnExitHook"), "files");
Assert.assertTrue(files.contains(tempFile.getPath()));
}
protected void closePeers(Socket socket, ServerSocket serverSocket)
throws IOException {
socket.close();
socket = serverSocket.accept();
socket.close();
}
protected void closeSocketChannel(
SocketChannel socketChannel, FileDescriptor fileDescriptor)
throws IOException {
ReflectionTestUtil.setFieldValue(socketChannel, "fd", fileDescriptor);
socketChannel.close();
}
protected SocketImpl swapSocketImpl(Socket socket, SocketImpl socketImpl) {
SocketImpl oldSocketImpl = ReflectionTestUtil.getFieldValue(
socket, "impl");
if (socketImpl == null) {
Socket unbindSocket = new Socket();
socketImpl = ReflectionTestUtil.getFieldValue(unbindSocket, "impl");
ReflectionTestUtil.setFieldValue(
socketImpl, "cmdsock",
new Socket() {
@Override
public synchronized void close() throws IOException {
throw new IOException();
}
});
}
ReflectionTestUtil.setFieldValue(socket, "impl", socketImpl);
return oldSocketImpl;
}
private static final String _SERVLET_CONTEXT_NAME = "SERVLET_CONTEXT_NAME";
private final MockHttpServletRequest _mockHttpServletRequest =
new MockHttpServletRequest();
private Portlet _portlet;
private final SPIConfiguration _spiConfiguration = new SPIConfiguration(
null, null, 1234, "baseDir", null, null, null);
private static class RecordSPIAgentResponse extends SPIAgentResponse {
public RecordSPIAgentResponse() {
super(_SERVLET_CONTEXT_NAME);
}
@Override
public void captureResponse(
HttpServletRequest request,
BufferCacheServletResponse bufferCacheServletResponse) {
_request = request;
_bufferCacheServletResponse = bufferCacheServletResponse;
}
@Override
public void writeTo(
RegistrationReference registrationReference,
OutputStream outputStream) {
_registrationReference = registrationReference;
_outputStream = outputStream;
}
private BufferCacheServletResponse _bufferCacheServletResponse;
private OutputStream _outputStream;
private RegistrationReference _registrationReference;
private HttpServletRequest _request;
}
}