@Test
  public void readIntoExceptionsTest() throws Exception {
    Channel channel = new MockChannel();
    // try to call readInto twice.
    NettyRequest nettyRequest = createNettyRequest(HttpMethod.POST, "/", null, channel);
    AsyncWritableChannel writeChannel = new ByteBufferAsyncWritableChannel();
    nettyRequest.readInto(writeChannel, null);

    try {
      nettyRequest.readInto(writeChannel, null);
      fail("Calling readInto twice should have failed");
    } catch (IllegalStateException e) {
      // expected. Nothing to do.
    }
    closeRequestAndValidate(nettyRequest, channel);

    // write into a channel that throws exceptions
    // non RuntimeException
    nettyRequest = createNettyRequest(HttpMethod.POST, "/", null, channel);
    List<HttpContent> httpContents = new ArrayList<HttpContent>();
    generateContent(httpContents);
    assertTrue("Not enough content has been generated", httpContents.size() > 2);
    String expectedMsg = "@@expectedMsg@@";
    Exception exception = new Exception(expectedMsg);
    writeChannel = new BadAsyncWritableChannel(exception);
    ReadIntoCallback callback = new ReadIntoCallback();

    // add content initially
    int addedCount = 0;
    for (; addedCount < httpContents.size() / 2; addedCount++) {
      HttpContent httpContent = httpContents.get(addedCount);
      nettyRequest.addContent(httpContent);
      assertEquals("Reference count is not as expected", 2, httpContent.refCnt());
    }
    Future<Long> future = nettyRequest.readInto(writeChannel, callback);

    // add some more content
    for (; addedCount < httpContents.size(); addedCount++) {
      HttpContent httpContent = httpContents.get(addedCount);
      nettyRequest.addContent(httpContent);
    }

    writeChannel.close();
    verifyRefCnts(httpContents);
    callback.awaitCallback();
    assertNotNull("Exception was not piped correctly", callback.exception);
    assertEquals("Exception message mismatch (callback)", expectedMsg, callback.exception.getMessage());
    try {
      future.get();
      fail("Future should have thrown exception");
    } catch (ExecutionException e) {
      assertEquals("Exception message mismatch (future)", expectedMsg, Utils.getRootCause(e).getMessage());
    }
    closeRequestAndValidate(nettyRequest, channel);

    // RuntimeException
    // during readInto
    nettyRequest = createNettyRequest(HttpMethod.POST, "/", null, channel);
    httpContents = new ArrayList<HttpContent>();
    generateContent(httpContents);
    exception = new IllegalStateException(expectedMsg);
    writeChannel = new BadAsyncWritableChannel(exception);
    callback = new ReadIntoCallback();

    for (HttpContent httpContent : httpContents) {
      nettyRequest.addContent(httpContent);
      assertEquals("Reference count is not as expected", 2, httpContent.refCnt());
    }
    try {
      nettyRequest.readInto(writeChannel, callback);
      fail("readInto did not throw expected exception");
    } catch (Exception e) {
      assertEquals("Exception caught does not match expected exception", expectedMsg, e.getMessage());
    }
    writeChannel.close();
    closeRequestAndValidate(nettyRequest, channel);
    verifyRefCnts(httpContents);

    // after readInto
    nettyRequest = createNettyRequest(HttpMethod.POST, "/", null, channel);
    httpContents = new ArrayList<HttpContent>();
    generateContent(httpContents);
    exception = new IllegalStateException(expectedMsg);
    writeChannel = new BadAsyncWritableChannel(exception);
    callback = new ReadIntoCallback();

    nettyRequest.readInto(writeChannel, callback);
    // add content
    HttpContent httpContent = httpContents.get(1);
    try {
      nettyRequest.addContent(httpContent);
      fail("addContent did not throw expected exception");
    } catch (Exception e) {
      assertEquals("Exception caught does not match expected exception", expectedMsg, e.getMessage());
    }
    writeChannel.close();
    closeRequestAndValidate(nettyRequest, channel);
    verifyRefCnts(httpContents);
  }
Tests exception scenarios of {@link NettyRequest#readInto(AsyncWritableChannel, Callback)} and behavior of
{@link NettyRequest} when {@link AsyncWritableChannel} instances fail.
@throws Exception
ambry-rest/src/test/java/com/github/ambry/rest/NettyRequestTest.java