private void doMultipartDecodeTest(int expectedRequestSize, InMemoryFile[] files, String digestAlgorithm)
      throws Exception {
    HttpHeaders httpHeaders = new DefaultHttpHeaders();
    httpHeaders.set(RestUtils.Headers.BLOB_SIZE, expectedRequestSize);
    NettyMultipartRequest request = createRequest(httpHeaders, files);
    assertEquals("Request size does not match", expectedRequestSize, request.getSize());
    request.prepare();

    RetainingAsyncWritableChannel asyncWritableChannel;
    byte[] readOutput;
    Map<String, Object> args = request.getArgs();
    ByteBuffer blobData = ByteBuffer.allocate(0);
    byte[] wholeDigest = null;
    if (files != null) {
      for (InMemoryFile file : files) {
        if (file.name.equals(RestUtils.MultipartPost.BLOB_PART)) {
          blobData = file.content;
          if (digestAlgorithm != null && !digestAlgorithm.isEmpty()) {
            MessageDigest digest = MessageDigest.getInstance(digestAlgorithm);
            digest.update(blobData);
            wholeDigest = digest.digest();
            blobData.rewind();
            request.setDigestAlgorithm(digestAlgorithm);
          }
        } else {
          Object value = args.get(file.name);
          assertNotNull("Request does not contain " + file, value);
          assertTrue("Argument value is not ByteBuffer", value instanceof ByteBuffer);
          readOutput = new byte[((ByteBuffer) value).remaining()];
          ((ByteBuffer) value).get(readOutput);
          assertArrayEquals(file.name + " content does not match", file.content.array(), readOutput);
        }
      }
    }
    asyncWritableChannel = new RetainingAsyncWritableChannel(expectedRequestSize);
    request.readInto(asyncWritableChannel, null).get();
    try (InputStream is = asyncWritableChannel.consumeContentAsInputStream()) {
      readOutput = Utils.readBytesFromStream(is, (int) asyncWritableChannel.getBytesWritten());
    }
    assertArrayEquals(RestUtils.MultipartPost.BLOB_PART + " content does not match", blobData.array(), readOutput);
    assertArrayEquals("Part by part digest should match digest of whole", wholeDigest, request.getDigest());
    closeRequestAndValidate(request);
  }
Does a multipart decode test.
1. Creates a {@link NettyMultipartRequest}.
2. Adds the {@link HttpRequest} and {@link HttpContent} generated by encoding the {@code files} as a multipart
request to the {@link NettyMultipartRequest}.
3. Reads data from the {@link NettyMultipartRequest} via read operations and
{@link NettyMultipartRequest#getArgs()} and verifies them against the source data ({@code files}).
@param expectedRequestSize the value expected on a call to {@link NettyMultipartRequest#getSize()}.
@param files the {@link InMemoryFile}s that form the parts of the multipart request.
@param digestAlgorithm the digest algorithm to use. Can be empty or {@code null} if digest checking is not
                       required.
@throws Exception
ambry-rest/src/test/java/com/github/ambry/rest/NettyMultipartRequestTest.java