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