@AdviseWith(adviceClasses = {Jdk14LogImplAdvice.class})
  @Test
  public void testSendDatagramWithCallback() throws Exception {

    // Submitted callback

    Pipe readPipe = Pipe.open();
    Pipe writePipe = Pipe.open();

    GatheringByteChannel gatheringByteChannel = writePipe.sink();
    ScatteringByteChannel scatteringByteChannel = readPipe.source();

    RegistrationReference registrationReference =
        _selectorIntraband.registerChannel(writePipe.source(), readPipe.sink());

    Object attachment = new Object();

    RecordCompletionHandler<Object> recordCompletionHandler = new RecordCompletionHandler<Object>();

    _selectorIntraband.sendDatagram(
        registrationReference,
        Datagram.createRequestDatagram(_type, _data),
        attachment,
        EnumSet.of(CompletionType.SUBMITTED),
        recordCompletionHandler);

    Datagram receiveDatagram = IntrabandTestUtil.readDatagramFully(scatteringByteChannel);

    recordCompletionHandler.waitUntilSubmitted();

    Assert.assertSame(attachment, recordCompletionHandler.getAttachment());
    Assert.assertEquals(_type, receiveDatagram.getType());

    ByteBuffer dataByteBuffer = receiveDatagram.getDataByteBuffer();

    Assert.assertArrayEquals(_data, dataByteBuffer.array());

    CaptureHandler captureHandler = null;

    try {

      // Callback timeout, with log

      captureHandler =
          JDKLoggerTestUtil.configureJDKLogger(BaseIntraband.class.getName(), Level.WARNING);

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      recordCompletionHandler = new RecordCompletionHandler<Object>();

      _selectorIntraband.sendDatagram(
          registrationReference,
          Datagram.createRequestDatagram(_type, _data),
          attachment,
          EnumSet.of(CompletionType.DELIVERED),
          recordCompletionHandler,
          10,
          TimeUnit.MILLISECONDS);

      Selector selector = _selectorIntraband.selector;

      recordCompletionHandler.waitUntilTimeouted(selector);

      Assert.assertSame(attachment, recordCompletionHandler.getAttachment());
      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(
          logRecords.get(0), "Removed timeout response waiting datagram");

      // Callback timeout, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      recordCompletionHandler = new RecordCompletionHandler<Object>();

      _selectorIntraband.sendDatagram(
          registrationReference,
          Datagram.createRequestDatagram(_type, _data),
          attachment,
          EnumSet.of(CompletionType.DELIVERED),
          recordCompletionHandler,
          10,
          TimeUnit.MILLISECONDS);

      recordCompletionHandler.waitUntilTimeouted(selector);

      Assert.assertSame(attachment, recordCompletionHandler.getAttachment());
      Assert.assertTrue(logRecords.isEmpty());
    } finally {
      if (captureHandler != null) {
        captureHandler.close();
      }
    }

    // Callback timeout, completion handler causes NPE

    captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(SelectorIntraband.class.getName(), Level.SEVERE);

    try {
      List<LogRecord> logRecords = captureHandler.getLogRecords();

      recordCompletionHandler =
          new RecordCompletionHandler<Object>() {

            @Override
            public void timedOut(Object attachment) {
              super.timedOut(attachment);

              throw new NullPointerException();
            }
          };

      Jdk14LogImplAdvice.reset();

      Selector selector = _selectorIntraband.selector;

      try {
        _selectorIntraband.sendDatagram(
            registrationReference,
            Datagram.createRequestDatagram(_type, _data),
            attachment,
            EnumSet.of(CompletionType.DELIVERED),
            recordCompletionHandler,
            10,
            TimeUnit.MILLISECONDS);
      } finally {
        recordCompletionHandler.waitUntilTimeouted(selector);

        Jdk14LogImplAdvice.waitUntilErrorCalled();
      }

      Assert.assertFalse(selector.isOpen());
      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(
          logRecords.get(0), SelectorIntraband.class + ".threadFactory-1 exiting exceptionally");

      gatheringByteChannel.close();
      scatteringByteChannel.close();
    } finally {
      captureHandler.close();
    }
  }
  @Test
  public void testCreateAndDestroy() throws Exception {
    CaptureHandler captureHandler = null;

    try {

      // Close selector, with log

      captureHandler =
          JDKLoggerTestUtil.configureJDKLogger(SelectorIntraband.class.getName(), Level.INFO);

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Thread wakeUpThread = new Thread(new WakeUpRunnable(_selectorIntraband));

      wakeUpThread.start();

      Thread pollingThread = _selectorIntraband.pollingThread;

      Selector selector = _selectorIntraband.selector;

      synchronized (selector) {
        wakeUpThread.interrupt();

        wakeUpThread.join();

        while (pollingThread.getState() != Thread.State.BLOCKED) ;

        selector.close();
      }

      pollingThread.join();

      Assert.assertEquals(1, logRecords.size());

      String pollingThreadName = pollingThread.getName();

      LogRecord logRecord = logRecords.get(0);

      Assert.assertEquals(
          pollingThreadName.concat(" exiting gracefully on selector closure"),
          logRecord.getMessage());

      // Close selector, without log

      _selectorIntraband = new SelectorIntraband(_DEFAULT_TIMEOUT);

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      wakeUpThread = new Thread(new WakeUpRunnable(_selectorIntraband));

      wakeUpThread.start();

      pollingThread = _selectorIntraband.pollingThread;

      selector = _selectorIntraband.selector;

      synchronized (selector) {
        wakeUpThread.interrupt();

        wakeUpThread.join();

        while (pollingThread.getState() != Thread.State.BLOCKED) ;

        selector.close();
      }

      pollingThread.join();

      Assert.assertTrue(logRecords.isEmpty());
    } finally {
      if (captureHandler != null) {
        captureHandler.close();
      }
    }
  }
  @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);

    CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

    try {

      // 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(1, logRecords.size());

      LogRecord logRecord = logRecords.get(0);

      Throwable throwable = logRecord.getThrown();

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

      swapSocketImpl(socket, socketImpl);
    } finally {
      captureHandler.close();
    }

    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();
  }
  @AdviseWith(adviceClasses = {Jdk14LogImplAdvice.class})
  @Test
  public void testReceiveDatagram() throws Exception {
    Pipe readPipe = Pipe.open();
    Pipe writePipe = Pipe.open();

    GatheringByteChannel gatheringByteChannel = writePipe.sink();
    ScatteringByteChannel scatteringByteChannel = readPipe.source();

    SelectionKeyRegistrationReference registrationReference =
        (SelectionKeyRegistrationReference)
            _selectorIntraband.registerChannel(writePipe.source(), readPipe.sink());

    long sequenceId = 100;

    CaptureHandler captureHandler = null;

    try {

      // Receive ACK response, no ACK request, with log

      captureHandler =
          JDKLoggerTestUtil.configureJDKLogger(BaseIntraband.class.getName(), Level.WARNING);

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(
            DatagramHelper.createACKResponseDatagram(sequenceId), gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilWarnCalled();
      }

      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(
          logRecords.get(0), "Dropped ownerless ACK response ");

      // Receive ACK response, no ACK request, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(
            DatagramHelper.createACKResponseDatagram(sequenceId), gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilIsWarnEnableCalled();
      }

      Assert.assertTrue(logRecords.isEmpty());

      // Receive ACK response, with ACK request

      Datagram requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setAttachment(requestDatagram, new Object());

      RecordCompletionHandler<Object> recordCompletionHandler =
          new RecordCompletionHandler<Object>();

      DatagramHelper.setCompletionHandler(requestDatagram, recordCompletionHandler);

      DatagramHelper.setSequenceId(requestDatagram, sequenceId);
      DatagramHelper.setTimeout(requestDatagram, 10000);

      BaseIntrabandHelper.addResponseWaitingDatagram(_selectorIntraband, requestDatagram);

      DatagramHelper.writeTo(
          DatagramHelper.createACKResponseDatagram(sequenceId), gatheringByteChannel);

      recordCompletionHandler.waitUntilDelivered();

      Assert.assertSame(
          DatagramHelper.getAttachment(requestDatagram), recordCompletionHandler.getAttachment());

      // Receive response, no request, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(
            Datagram.createResponseDatagram(requestDatagram, _data), gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilWarnCalled();
      }

      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(logRecords.get(0), "Dropped ownerless response ");

      // Receive response, no request, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Jdk14LogImplAdvice.reset();

      try {
        requestDatagram = Datagram.createRequestDatagram(_type, _data);

        DatagramHelper.setSequenceId(requestDatagram, sequenceId);

        DatagramHelper.writeTo(
            Datagram.createResponseDatagram(requestDatagram, _data), gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilIsWarnEnableCalled();
      }

      Assert.assertTrue(logRecords.isEmpty());

      // Receive response, with request, with replied completion handler

      requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setAttachment(requestDatagram, new Object());

      recordCompletionHandler = new RecordCompletionHandler<Object>();

      DatagramHelper.setCompletionHandler(requestDatagram, recordCompletionHandler);

      DatagramHelper.setCompletionTypes(requestDatagram, EnumSet.of(CompletionType.REPLIED));
      DatagramHelper.setSequenceId(requestDatagram, sequenceId);
      DatagramHelper.setTimeout(requestDatagram, 10000);

      BaseIntrabandHelper.addResponseWaitingDatagram(_selectorIntraband, requestDatagram);

      DatagramHelper.writeTo(
          Datagram.createResponseDatagram(requestDatagram, _data), gatheringByteChannel);

      recordCompletionHandler.waitUntilReplied();

      Assert.assertSame(
          DatagramHelper.getAttachment(requestDatagram), recordCompletionHandler.getAttachment());

      // Receive response, with request, without replied completion
      // handler, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setCompletionTypes(requestDatagram, EnumSet.noneOf(CompletionType.class));

      recordCompletionHandler = new RecordCompletionHandler<Object>();

      DatagramHelper.setCompletionHandler(requestDatagram, recordCompletionHandler);

      DatagramHelper.setSequenceId(requestDatagram, sequenceId);
      DatagramHelper.setTimeout(requestDatagram, 10000);

      BaseIntrabandHelper.addResponseWaitingDatagram(_selectorIntraband, requestDatagram);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(
            Datagram.createResponseDatagram(requestDatagram, _data), gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilWarnCalled();
      }

      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(logRecords.get(0), "Dropped unconcerned response ");

      // Receive response, with request, without replied completion
      // handler, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setCompletionTypes(requestDatagram, EnumSet.noneOf(CompletionType.class));

      recordCompletionHandler = new RecordCompletionHandler<Object>();

      DatagramHelper.setCompletionHandler(requestDatagram, recordCompletionHandler);

      DatagramHelper.setSequenceId(requestDatagram, sequenceId);
      DatagramHelper.setTimeout(requestDatagram, 10000);

      BaseIntrabandHelper.addResponseWaitingDatagram(_selectorIntraband, requestDatagram);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(
            Datagram.createResponseDatagram(requestDatagram, _data), gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilIsWarnEnableCalled();
      }

      Assert.assertTrue(logRecords.isEmpty());

      // Receive request, requires ACK, no datagram receive handler,
      // with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setAckRequest(requestDatagram);
      DatagramHelper.setSequenceId(requestDatagram, sequenceId);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(requestDatagram, gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilWarnCalled();
      }

      Datagram ackResponseDatagram = IntrabandTestUtil.readDatagramFully(scatteringByteChannel);

      Assert.assertEquals(sequenceId, DatagramHelper.getSequenceId(ackResponseDatagram));
      Assert.assertTrue(DatagramHelper.isAckResponse(ackResponseDatagram));

      ByteBuffer dataByteBuffer = ackResponseDatagram.getDataByteBuffer();

      Assert.assertEquals(0, dataByteBuffer.capacity());

      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(logRecords.get(0), "Dropped ownerless request ");

      // Receive request, no datagram receive handler, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setSequenceId(requestDatagram, sequenceId);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(requestDatagram, gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilIsWarnEnableCalled();
      }

      Assert.assertTrue(logRecords.isEmpty());

      // Receive request, with datagram receive handler,

      logRecords = captureHandler.resetLogLevel(Level.SEVERE);

      requestDatagram = Datagram.createRequestDatagram(_type, _data);

      DatagramHelper.setSequenceId(requestDatagram, sequenceId);

      RecordDatagramReceiveHandler recordDatagramReceiveHandler =
          new RecordDatagramReceiveHandler();

      _selectorIntraband.registerDatagramReceiveHandler(_type, recordDatagramReceiveHandler);

      Jdk14LogImplAdvice.reset();

      try {
        DatagramHelper.writeTo(requestDatagram, gatheringByteChannel);
      } finally {
        Jdk14LogImplAdvice.waitUntilErrorCalled();
      }

      Datagram receiveDatagram = recordDatagramReceiveHandler.getReceiveDatagram();

      Assert.assertEquals(sequenceId, DatagramHelper.getSequenceId(receiveDatagram));
      Assert.assertEquals(_type, receiveDatagram.getType());

      dataByteBuffer = receiveDatagram.getDataByteBuffer();

      Assert.assertArrayEquals(_data, dataByteBuffer.array());
      Assert.assertEquals(1, logRecords.size());

      IntrabandTestUtil.assertMessageStartWith(logRecords.get(0), "Unable to dispatch");

      unregisterChannels(registrationReference);

      gatheringByteChannel.close();
      scatteringByteChannel.close();
    } finally {
      if (captureHandler != null) {
        captureHandler.close();
      }
    }
  }
  @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);

      CaptureHandler captureHandler =
          JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

      try {

        // 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(1, logRecords.size());

        LogRecord logRecord = logRecords.get(0);

        Throwable throwable = logRecord.getThrown();

        Assert.assertSame(IOException.class, throwable.getClass());
      } finally {
        captureHandler.close();
      }

      // 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 testDestroy() throws Exception {
    CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

    try {

      // 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(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());
      }
    } finally {
      captureHandler.close();
    }
  }
  @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();

      CaptureHandler captureHandler =
          JDKLoggerTestUtil.configureJDKLogger(HttpClientSPIAgent.class.getName(), Level.OFF);

      try {

        // 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(1, logRecords.size());

        LogRecord logRecord = logRecords.get(0);

        Throwable throwable = logRecord.getThrown();

        Assert.assertSame(IOException.class, throwable.getClass());
      } finally {
        captureHandler.close();
      }

      // 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);
    }
  }
  @AdviseWith(adviceClasses = {PropsUtilAdvice.class})
  @Test
  public void testSPIRegistration() {
    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(MPIHelperUtil.class.getName(), Level.WARNING)) {

      // Mismatch MPI, with log

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      MockSPI mockSPI1 = new MockSPI();

      mockSPI1.mpi = new MockMPI();

      Assert.assertFalse(MPIHelperUtil.registerSPI(mockSPI1));

      LogRecord logRecord = logRecords.get(0);

      Assert.assertEquals(
          "Not registering SPI "
              + mockSPI1
              + " with foreign MPI "
              + mockSPI1.mpi
              + " versus "
              + MPIHelperUtil.getMPI(),
          logRecord.getMessage());

      // Mismatch MPI, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertFalse(MPIHelperUtil.registerSPI(mockSPI1));
      Assert.assertTrue(logRecords.isEmpty());

      // Null SPI provider name

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiProviderName = null;

      try {
        MPIHelperUtil.registerSPI(mockSPI1);

        Assert.fail();
      } catch (NullPointerException npe) {
      }

      // No such SPI provider, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiProviderName = "name1";

      Assert.assertFalse(MPIHelperUtil.registerSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals(
          "Not registering SPI "
              + mockSPI1
              + " with unknown SPI provider "
              + mockSPI1.spiProviderName,
          logRecord.getMessage());

      // No such SPI provider, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiProviderName = "name1";

      Assert.assertFalse(MPIHelperUtil.registerSPI(mockSPI1));
      Assert.assertTrue(logRecords.isEmpty());

      // Successful register, with log

      String name = "name1";

      MockSPIProvider mockSPIProvider = new MockSPIProvider(name);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider));

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiConfiguration =
          new SPIConfiguration(
              "testId1", "", 8081, "", new String[0], new String[] {"servletContextName1"}, null);
      mockSPI1.spiProviderName = name;

      logRecords = captureHandler.resetLogLevel(Level.INFO);

      Assert.assertTrue(MPIHelperUtil.registerSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals("Registered SPI " + mockSPI1, logRecord.getMessage());

      // Successful register, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      MessagingConfigurator messagingConfigurator =
          new AbstractMessagingConfigurator() {

            @Override
            public void connect() {}

            @Override
            public void disconnect() {}

            @Override
            protected MessageBus getMessageBus() {
              return null;
            }

            @Override
            protected ClassLoader getOperatingClassloader() {
              return null;
            }
          };

      MessagingConfiguratorRegistry.registerMessagingConfigurator(
          "servletContextName2", messagingConfigurator);

      MockSPI mockSPI2 = new MockSPI();

      mockSPI2.mpi = MPIHelperUtil.getMPI();
      mockSPI2.spiConfiguration =
          new SPIConfiguration(
              "testId2", "", 8082, "", new String[0], new String[] {"servletContextName2"}, null);
      mockSPI2.spiProviderName = name;

      Assert.assertTrue(MPIHelperUtil.registerSPI(mockSPI2));
      Assert.assertTrue(logRecords.isEmpty());

      // Duplicate register, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      Assert.assertFalse(MPIHelperUtil.registerSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals(
          "Not registering SPI " + mockSPI1 + " because it duplicates " + mockSPI1,
          logRecord.getMessage());

      // Duplicate register, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertFalse(MPIHelperUtil.registerSPI(mockSPI2));
      Assert.assertTrue(logRecords.isEmpty());

      // Bad SPI impl

      mockSPI1 = new MockSPI();

      mockSPI1.failOnGetConfiguration = true;
      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiProviderName = name;

      try {
        MPIHelperUtil.registerSPI(mockSPI1);

        Assert.fail();
      } catch (RuntimeException re) {
        Throwable throwable = re.getCause();

        Assert.assertSame(RemoteException.class, throwable.getClass());
      }

      // Get SPI, no such SPI provider

      Assert.assertNull(MPIHelperUtil.getSPI("name2", "testId1"));

      // Get SPI, exists

      Assert.assertNotNull(MPIHelperUtil.getSPI(name, "testId1"));

      // Get SPI, does not exist

      Assert.assertNull(MPIHelperUtil.getSPI(name, "testId3"));

      // Get SPIs

      logRecords = captureHandler.resetLogLevel(Level.SEVERE);

      mockSPI2.failOnIsAlive = true;

      List<SPI> spis = MPIHelperUtil.getSPIs();

      Assert.assertEquals(1, spis.size());

      mockSPI1 = (MockSPI) spis.get(0);

      Assert.assertEquals(name, mockSPI1.spiProviderName);
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Throwable throwable = logRecord.getThrown();

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

      // Get SPIs by SPI provider, exists

      mockSPI2 = new MockSPI();

      mockSPI2.mpi = MPIHelperUtil.getMPI();
      mockSPI2.spiConfiguration =
          new SPIConfiguration("testId2", "", 8082, "", new String[0], new String[0], null);
      mockSPI2.spiProviderName = name;

      Assert.assertTrue(MPIHelperUtil.registerSPI(mockSPI2));

      mockSPI2.failOnIsAlive = true;

      spis = MPIHelperUtil.getSPIs(name);

      Assert.assertEquals(1, spis.size());

      mockSPI1 = (MockSPI) spis.get(0);

      Assert.assertEquals(name, mockSPI1.spiProviderName);

      // Get SPIs by SPI provider, does not exist

      spis = MPIHelperUtil.getSPIs("name2");

      Assert.assertTrue(spis.isEmpty());

      // Unregister thread local shortcut, with log

      mockSPI1 = new MockSPI();

      mockSPI1.spiConfiguration =
          new SPIConfiguration(null, null, 0, null, null, new String[0], null);

      ThreadLocal<SPI> unregisteringSPIThreadLocal =
          ReflectionTestUtil.getFieldValue(MPIHelperUtil.class, "_unregisteringSPIThreadLocal");

      unregisteringSPIThreadLocal.set(mockSPI1);

      try {
        Assert.assertTrue(MPIHelperUtil.unregisterSPI(mockSPI1));
      } finally {
        unregisteringSPIThreadLocal.remove();
      }

      // Unregister MPI mismatch, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = new MockMPI();

      Assert.assertFalse(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals(
          "Not unregistering SPI "
              + mockSPI1
              + " with foreign MPI "
              + mockSPI1.mpi
              + " versus "
              + MPIHelperUtil.getMPI(),
          logRecord.getMessage());

      // Unregister MPI mismatch, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertFalse(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister no such SPI provider, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiProviderName = "name2";

      Assert.assertFalse(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals(
          "Not unregistering SPI "
              + mockSPI1
              + " with unknown SPI provider "
              + mockSPI1.spiProviderName,
          logRecord.getMessage());

      // Unregister no such SPI provider, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiProviderName = "name2";

      Assert.assertFalse(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister no such SPI, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiConfiguration =
          new SPIConfiguration("testId3", "", 8083, "", new String[0], new String[0], null);
      mockSPI1.spiProviderName = name;

      Assert.assertFalse(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals("Not unregistering unregistered SPI " + mockSPI1, logRecord.getMessage());

      // Unregister no such SPI, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPI1 = new MockSPI();

      mockSPI1.mpi = MPIHelperUtil.getMPI();
      mockSPI1.spiConfiguration =
          new SPIConfiguration("testId3", "", 8083, "", new String[0], new String[0], null);
      mockSPI1.spiProviderName = name;

      Assert.assertFalse(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister success, with log

      mockSPI1 = (MockSPI) MPIHelperUtil.getSPI(name, "testId1");

      logRecords = captureHandler.resetLogLevel(Level.INFO);

      Assert.assertTrue(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertEquals(1, logRecords.size());

      logRecord = logRecords.get(0);

      Assert.assertEquals("Unregistered SPI " + mockSPI1, logRecord.getMessage());

      // Unregister success, without log

      Assert.assertTrue(MPIHelperUtil.registerSPI(mockSPI1));

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertTrue(MPIHelperUtil.unregisterSPI(mockSPI1));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister fail on getting configuration

      mockSPI1.failOnGetConfiguration = true;

      try {
        MPIHelperUtil.unregisterSPI(mockSPI1);

        Assert.fail();
      } catch (RuntimeException re) {
        throwable = re.getCause();

        Assert.assertSame(RemoteException.class, throwable.getClass());
      }
    }
  }
  @AdviseWith(adviceClasses = {PropsUtilAdvice.class})
  @Test
  public void testSPIProviderRegistration() throws RemoteException {

    // Register SPI provider, null name

    MockSPIProvider mockSPIProvider1 = new MockSPIProvider(null);

    try {
      MPIHelperUtil.registerSPIProvider(mockSPIProvider1);

      Assert.fail();
    } catch (NullPointerException npe) {
    }

    try (CaptureHandler captureHandler =
        JDKLoggerTestUtil.configureJDKLogger(MPIHelperUtil.class.getName(), Level.INFO)) {

      // Register SPI provider, with log

      List<LogRecord> logRecords = captureHandler.getLogRecords();

      String name1 = "spiProvider1";

      mockSPIProvider1 = new MockSPIProvider(name1);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider1));
      Assert.assertEquals(1, logRecords.size());

      LogRecord logRecord1 = logRecords.get(0);

      Assert.assertEquals("Registered SPI provider " + mockSPIProvider1, logRecord1.getMessage());

      // Register SPI provider, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      String name2 = "spiProvider2";

      MockSPIProvider mockSPIProvider2 = new MockSPIProvider(name2);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider2));
      Assert.assertTrue(logRecords.isEmpty());

      // Register SPI provider, duplicate name, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      MockSPIProvider mockSPIProvider3 = new MockSPIProvider(name1);

      Assert.assertFalse(MPIHelperUtil.registerSPIProvider(mockSPIProvider3));
      Assert.assertEquals(1, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals(
          "Not registering SPI provider "
              + mockSPIProvider3
              + " because it duplicates "
              + mockSPIProvider1,
          logRecord1.getMessage());

      // Register SPI provider, duplicate name, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPIProvider3 = new MockSPIProvider(name1);

      Assert.assertFalse(MPIHelperUtil.registerSPIProvider(mockSPIProvider3));
      Assert.assertTrue(logRecords.isEmpty());

      // Get SPI provider

      String name3 = "spiProvider3";

      Assert.assertSame(mockSPIProvider1, MPIHelperUtil.getSPIProvider(name1));
      Assert.assertSame(mockSPIProvider2, MPIHelperUtil.getSPIProvider(name2));
      Assert.assertNull(MPIHelperUtil.getSPIProvider(name3));

      List<SPIProvider> spiProviders = MPIHelperUtil.getSPIProviders();

      Assert.assertEquals(2, spiProviders.size());
      Assert.assertTrue(spiProviders.contains(mockSPIProvider1));
      Assert.assertTrue(spiProviders.contains(mockSPIProvider2));

      // Unregister SPI provider, null name

      mockSPIProvider3 = new MockSPIProvider(null);

      try {
        MPIHelperUtil.unregisterSPIProvider(mockSPIProvider3);

        Assert.fail();
      } catch (NullPointerException npe) {
      }

      // Unregister SPI provider, nonexistent name, with log

      logRecords = captureHandler.resetLogLevel(Level.WARNING);

      mockSPIProvider3 = new MockSPIProvider(name3);

      Assert.assertFalse(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider3));
      Assert.assertEquals(1, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals(
          "Not unregistering unregistered SPI provider " + mockSPIProvider3,
          logRecord1.getMessage());

      // Unregister SPI provider, nonexistent name, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPIProvider3 = new MockSPIProvider(name3);

      Assert.assertFalse(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider3));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister SPI provider, mismatch instance, with log

      logRecords = captureHandler.resetLogLevel(Level.INFO);

      Assert.assertFalse(MPIHelperUtil.unregisterSPIProvider(new MockSPIProvider(name2)));
      Assert.assertEquals(1, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals(
          "Not unregistering unregistered SPI provider " + name2, logRecord1.getMessage());

      // Unregister SPI provider, mismatch instance, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertFalse(MPIHelperUtil.unregisterSPIProvider(new MockSPIProvider(name2)));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister SPI provider, concurrent remove failure, with log

      logRecords = captureHandler.resetLogLevel(Level.INFO);

      ConcurrentMap<String, Object> oldSPIProviderContainers =
          ReflectionTestUtil.getFieldValue(MPIHelperUtil.class, "_spiProviderContainers");

      try {
        ReflectionTestUtil.setFieldValue(
            MPIHelperUtil.class,
            "_spiProviderContainers",
            new ConcurrentHashMap<String, Object>(oldSPIProviderContainers) {

              @Override
              public boolean remove(Object key, Object value) {
                return false;
              }
            });

        Assert.assertFalse(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider2));
      } finally {
        ReflectionTestUtil.setFieldValue(
            MPIHelperUtil.class, "_spiProviderContainers", oldSPIProviderContainers);
      }

      Assert.assertEquals(1, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals(
          "Not unregistering unregistered SPI provider " + name2, logRecord1.getMessage());

      // Unregister SPI provider, concurrent remove failure, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      oldSPIProviderContainers =
          ReflectionTestUtil.getFieldValue(MPIHelperUtil.class, "_spiProviderContainers");

      try {
        ReflectionTestUtil.setFieldValue(
            MPIHelperUtil.class,
            "_spiProviderContainers",
            new ConcurrentHashMap<String, Object>(oldSPIProviderContainers) {

              @Override
              public boolean remove(Object key, Object value) {
                return false;
              }
            });

        Assert.assertFalse(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider2));
      } finally {
        ReflectionTestUtil.setFieldValue(
            MPIHelperUtil.class, "_spiProviderContainers", oldSPIProviderContainers);
      }

      Assert.assertTrue(logRecords.isEmpty());

      // Unregister SPI provider, with no SPI, with log

      logRecords = captureHandler.resetLogLevel(Level.INFO);

      Assert.assertTrue(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider2));
      Assert.assertEquals(1, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals("Unregistered SPI provider " + mockSPIProvider2, logRecord1.getMessage());

      // Unregister SPI provider, with no SPI, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertTrue(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider1));
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister SPI provider, with SPI, fail on stop, with log

      logRecords = captureHandler.resetLogLevel(Level.SEVERE);

      mockSPIProvider1 = new MockSPIProvider(name1);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider1));

      mockSPIProvider2 = new MockSPIProvider(name2);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider2));

      MockSPI mockSPI1 = new MockSPI();

      mockSPI1.failOnStop = true;
      mockSPI1.spiProviderName = name1;

      MPIHelperUtilTestUtil.directResigterSPI("spi1", mockSPI1);

      MockSPI mockSPI2 = new MockSPI();

      mockSPI2.failOnStop = true;
      mockSPI2.spiProviderName = name2;

      MPIHelperUtilTestUtil.directResigterSPI("spi2", mockSPI2);

      Assert.assertTrue(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider1));
      Assert.assertFalse(mockSPI1.destroyed);
      Assert.assertFalse(mockSPI1.stopped);
      Assert.assertFalse(mockSPI2.destroyed);
      Assert.assertFalse(mockSPI2.stopped);
      Assert.assertEquals(1, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals(
          "Unable to unregister SPI "
              + mockSPI1
              + " while unregistering SPI provider "
              + mockSPIProvider1,
          logRecord1.getMessage());

      Throwable throwable = logRecord1.getThrown();

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

      // Unregister SPI provider, with SPI, fail on destroy, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPI1.failOnDestroy = true;
      mockSPI1.failOnStop = false;

      mockSPI2.failOnDestroy = true;
      mockSPI2.failOnStop = false;

      Assert.assertTrue(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider2));
      Assert.assertFalse(mockSPI1.destroyed);
      Assert.assertFalse(mockSPI1.stopped);
      Assert.assertFalse(mockSPI2.destroyed);
      Assert.assertTrue(mockSPI2.stopped);
      Assert.assertTrue(logRecords.isEmpty());

      // Unregister SPI provider, with SPI, fail on catch, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      mockSPIProvider1 = new MockSPIProvider(name1);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider1));

      final RuntimeException runtimeException = new RuntimeException();

      mockSPI1 =
          new MockSPI() {

            @Override
            public String toString() {
              throw runtimeException;
            }
          };

      mockSPI1.failOnDestroy = true;
      mockSPI1.failOnStop = false;
      mockSPI1.spiProviderName = name1;

      MPIHelperUtilTestUtil.directResigterSPI(name1, mockSPI1);

      try {
        MPIHelperUtil.unregisterSPIProvider(mockSPIProvider1);

        Assert.fail();
      } catch (RuntimeException re) {
        Assert.assertSame(runtimeException, re);
      }

      Assert.assertTrue(logRecords.isEmpty());

      // Unregister SPI provider, with SPI, success, with log

      mockSPIProvider1 = new MockSPIProvider(name1);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider1));

      mockSPIProvider2 = new MockSPIProvider(name2);

      Assert.assertTrue(MPIHelperUtil.registerSPIProvider(mockSPIProvider2));

      mockSPI1 = new MockSPI();

      mockSPI1.failOnDestroy = false;
      mockSPI1.spiProviderName = name1;

      MPIHelperUtilTestUtil.directResigterSPI("spi1", mockSPI1);

      mockSPI2 = new MockSPI();

      mockSPI2.failOnDestroy = false;
      mockSPI2.spiProviderName = name2;

      MPIHelperUtilTestUtil.directResigterSPI("spi2", mockSPI2);

      logRecords = captureHandler.resetLogLevel(Level.INFO);

      Assert.assertTrue(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider1));
      Assert.assertTrue(mockSPI1.destroyed);
      Assert.assertTrue(mockSPI1.stopped);
      Assert.assertFalse(mockSPI2.destroyed);
      Assert.assertFalse(mockSPI2.stopped);
      Assert.assertEquals(2, logRecords.size());

      logRecord1 = logRecords.get(0);

      Assert.assertEquals(
          "Unregistered SPI " + mockSPI1 + " while unregistering SPI provider " + mockSPIProvider1,
          logRecord1.getMessage());

      LogRecord logRecord2 = logRecords.get(1);

      Assert.assertEquals("Unregistered SPI provider " + mockSPIProvider1, logRecord2.getMessage());

      // Unregister SPI provider, with SPI, success, without log

      logRecords = captureHandler.resetLogLevel(Level.OFF);

      Assert.assertTrue(MPIHelperUtil.unregisterSPIProvider(mockSPIProvider2));
      Assert.assertTrue(mockSPI1.destroyed);
      Assert.assertTrue(mockSPI1.stopped);
      Assert.assertTrue(mockSPI2.destroyed);
      Assert.assertTrue(mockSPI2.stopped);
      Assert.assertTrue(logRecords.isEmpty());
    }
  }