@Test
  public void testS3MultipartETag() throws Exception {
    List<Pair<String, Long>> orgList = new ArrayList<>();
    int chunkCount = 100;
    for (int i = 0; i < chunkCount; i++) {
      orgList.add(new Pair<>(String.valueOf(random.nextLong()), random.nextLong()));
    }

    S3MultipartETag orgETag = new S3MultipartETag(orgList);

    // Serialize and Deserialize, the S3MultipartETag should be the same
    String eTagstr = S3MultipartETag.serialize(orgETag);
    S3MultipartETag deserializedETag = S3MultipartETag.deserialize(eTagstr);
    Assert.assertEquals(orgETag, deserializedETag);
    List<Pair<String, Long>> deserializedList = deserializedETag.getOrderedChunkIdSizeList();
    for (int i = 0; i < chunkCount; i++) {
      Assert.assertEquals(orgList.get(i).getFirst(), deserializedList.get(i).getFirst());
      Assert.assertEquals(orgList.get(i).getSecond(), deserializedList.get(i).getSecond());
    }
  }
Test the S3 Multipart upload
1. Part Upload: Test the PutBlob with skipCompositeChunk option. We don't generate composite chunk for it.
Instead, we return PutBlobMetaInfo which includes the data chunk list.
No matter if router enables "reserved metadata chunk" feature, S3 part upload doesn't reserve metadata chunk.
2. Stitch Blob: It's called in completeMultipartUpload. It stitches all data chunks.
@throws Exception
ambry-router/src/test/java/com/github/ambry/router/S3NonBlockingRouterTest.java