private void doContentAddAndReadTest(String digestAlgorithm, ByteBuffer content, List<HttpContent> httpContents,
      int numChunksToAddBeforeRead, HttpMethod method) throws Exception {
    if (numChunksToAddBeforeRead < 0 || numChunksToAddBeforeRead > httpContents.size()) {
      throw new IllegalArgumentException("Illegal value of numChunksToAddBeforeRead");
    }

    Channel channel = new MockChannel();
    NettyRequest nettyRequest = createNettyRequest(method, "/", null, channel);
    byte[] wholeDigest = null;
    if (digestAlgorithm != null && !digestAlgorithm.isEmpty()) {
      MessageDigest digest = MessageDigest.getInstance(digestAlgorithm);
      digest.update(content);
      wholeDigest = digest.digest();
      content.rewind();
      nettyRequest.setDigestAlgorithm(digestAlgorithm);
    }

    int bytesToVerify = 0;
    int addedCount = 0;
    for (; addedCount < numChunksToAddBeforeRead; addedCount++) {
      HttpContent httpContent = httpContents.get(addedCount);
      bytesToVerify += httpContent.content().readableBytes();
      nettyRequest.addContent(httpContent);
      // ref count always 2 when added before calling readInto()
      assertEquals("Reference count is not as expected", 2, httpContent.refCnt());
    }
    ByteBufferAsyncWritableChannel writeChannel = new ByteBufferAsyncWritableChannel();
    ReadIntoCallback callback = new ReadIntoCallback();
    Future<Long> future = nettyRequest.readInto(writeChannel, callback);
    readAndVerify(bytesToVerify, writeChannel, content);

    bytesToVerify = 0;
    for (; addedCount < httpContents.size(); addedCount++) {
      HttpContent httpContent = httpContents.get(addedCount);
      bytesToVerify += httpContent.content().readableBytes();
      nettyRequest.addContent(httpContent);
      assertEquals("Reference count is not as expected", 2, httpContent.refCnt());
    }
    readAndVerify(bytesToVerify, writeChannel, content);
    verifyRefCnts(httpContents);
    writeChannel.close();
    callback.awaitCallback();
    if (callback.exception != null) {
      throw callback.exception;
    }
    long futureBytesRead = future.get();
    assertEquals("Total bytes read does not match (callback)", content.limit(), callback.bytesRead);
    assertEquals("Total bytes read does not match (future)", content.limit(), futureBytesRead);
    assertEquals("nettyRequest.getBytesReceived() does not match expected", content.limit(),
        nettyRequest.getBytesReceived());

    // check twice to make sure the same digest is returned every time
    for (int i = 0; i < 2; i++) {
      assertArrayEquals("Part by part digest should match digest of whole", wholeDigest, nettyRequest.getDigest());
    }
    closeRequestAndValidate(nettyRequest, channel);
  }
Does the content addition and read verification based on the arguments provided.
@param digestAlgorithm the digest algorithm to use. Can be empty or {@code null} if digest checking is not
                       required.
@param content the complete content.
@param httpContents {@code content} in parts and as {@link HttpContent}. Should contain all the data in
{@code content}.
@param numChunksToAddBeforeRead the number of {@link HttpContent} to add before making the
{@link NettyRequest#readInto(AsyncWritableChannel, Callback)} call.
@param method Http method
@throws Exception
ambry-rest/src/test/java/com/github/ambry/rest/NettyRequestTest.java