@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);
  }
  public HttpClientSPIAgent(
      SPIConfiguration spiConfiguration, RegistrationReference registrationReference)
      throws UnknownHostException {

    this.registrationReference = registrationReference;

    socketAddress =
        new InetSocketAddress(
            InetAddressUtil.getLoopbackInetAddress(), spiConfiguration.getConnectorPort());
    socketBlockingQueue =
        new ArrayBlockingQueue<>(PropsValues.PORTAL_RESILIENCY_SPI_AGENT_CLIENT_POOL_MAX_SIZE);

    String httpServletRequestContentString =
        "POST "
            + SPI_AGENT_CONTEXT_PATH
            + MAPPING_PATTERN
            + " HTTP/1.1\r\nHost: localhost:"
            + spiConfiguration.getConnectorPort()
            + "\r\n"
            + "Content-Length: 8\r\n\r\n";

    httpServletRequestContent =
        httpServletRequestContentString.getBytes(Charset.forName("US-ASCII"));
  }
  @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

    httpClientSPIAgent =
        new HttpClientSPIAgent(
            _spiConfiguration,
            new MockRegistrationReference(new DirectMailboxIntraBand(new IOException())));

    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());
    }

    ServerSocket serverSocket = serverSocketChannel.socket();

    closePeers(socket, serverSocket);

    // Unable to send, unable to close, without log

    List<LogRecord> logRecords =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

    socket =
        new Socket(InetAddressUtil.getLoopbackInetAddress(), _spiConfiguration.getConnectorPort());

    SocketImpl socketImpl = swapSocketImpl(socket, null);

    DirectMailboxIntraBand directMailboxIntraBand = new DirectMailboxIntraBand(new IOException());

    httpClientSPIAgent =
        new HttpClientSPIAgent(
            _spiConfiguration, new MockRegistrationReference(directMailboxIntraBand));

    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 =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.WARNING);

    socket =
        new Socket(InetAddressUtil.getLoopbackInetAddress(), _spiConfiguration.getConnectorPort());

    socketImpl = swapSocketImpl(socket, null);

    directMailboxIntraBand = new DirectMailboxIntraBand(new IOException());

    httpClientSPIAgent =
        new HttpClientSPIAgent(
            _spiConfiguration, new MockRegistrationReference(directMailboxIntraBand));

    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(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);

    httpClientSPIAgent =
        new HttpClientSPIAgent(
            _spiConfiguration, new MockRegistrationReference(new DirectMailboxIntraBand(null)));

    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));

    Method depositMailMethod =
        ReflectionUtil.getDeclaredMethod(MailboxUtil.class, "depositMail", ByteBuffer.class);

    long receipt = (Long) depositMailMethod.invoke(null, 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 testReturnSocket() throws Exception {

    // Force close, successfully

    ServerSocketChannel serverSocketChannel =
        SocketUtil.createServerSocketChannel(
            InetAddressUtil.getLoopbackInetAddress(), _spiConfiguration.getConnectorPort(), null);

    serverSocketChannel.configureBlocking(true);

    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);

    // Force close, failed without log

    List<LogRecord> logRecords =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

    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 =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), 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(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);

    serverSocket.close();
  }
  @Test
  public void testDestroy() throws Exception {

    // Without log

    List<LogRecord> logRecords =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

    ServerSocketChannel serverSocketChannel =
        SocketUtil.createServerSocketChannel(
            InetAddressUtil.getLoopbackInetAddress(), _spiConfiguration.getConnectorPort(), null);

    serverSocketChannel.configureBlocking(true);

    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());

    // With log

    logRecords =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), 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(1, logRecords.size());

    LogRecord logRecord = logRecords.get(0);

    Throwable throwable = logRecord.getThrown();

    Assert.assertSame(IOException.class, throwable.getClass());

    serverSocket.close();
  }
  @Test
  public void testBorrowSocket() throws Exception {

    // Create on empty

    ServerSocketChannel serverSocketChannel =
        SocketUtil.createServerSocketChannel(
            InetAddressUtil.getLoopbackInetAddress(), _spiConfiguration.getConnectorPort(), null);

    serverSocketChannel.configureBlocking(true);

    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();

    // Clean up when input is shutdown, failed without log

    List<LogRecord> logRecords =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

    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 =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), 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(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);

    serverSocket.close();
  }