private void doReplicaMetadataRequestTest(short responseVersionToUse, short requestVersionToUse,
      short messageInfoToUse, ReplicaType replicaType) throws IOException {
    MessageInfoAndMetadataListSerde.AUTO_VERSION = messageInfoToUse;
    MockClusterMap clusterMap = new MockClusterMap();
    List<ReplicaMetadataRequestInfo> replicaMetadataRequestInfoList = new ArrayList<ReplicaMetadataRequestInfo>();
    ReplicaMetadataRequestInfo replicaMetadataRequestInfo =
        new ReplicaMetadataRequestInfo(new MockPartitionId(), new MockFindToken(0, 1000), "localhost", "path",
            replicaType, requestVersionToUse);
    replicaMetadataRequestInfoList.add(replicaMetadataRequestInfo);
    ReplicaMetadataRequest request =
        new ReplicaMetadataRequest(1, "id", replicaMetadataRequestInfoList, 1000, requestVersionToUse);
    DataInputStream requestStream = serAndPrepForRead(request, -1, true);
    ReplicaMetadataRequest replicaMetadataRequestFromBytes =
        ReplicaMetadataRequest.readFrom(requestStream, new MockClusterMap(), new MockFindTokenHelper());
    Assert.assertEquals(replicaMetadataRequestFromBytes.getMaxTotalSizeOfEntriesInBytes(), 1000);
    Assert.assertEquals(replicaMetadataRequestFromBytes.getReplicaMetadataRequestInfoList().size(), 1);
    request.release();

    try {
      new ReplicaMetadataRequest(1, "id", null, 12, requestVersionToUse);
      Assert.fail("Serializing should have failed");
    } catch (IllegalArgumentException e) {
      // expected. Nothing to do
    }
    try {
      new ReplicaMetadataRequestInfo(new MockPartitionId(), null, "localhost", "path", replicaType,
          requestVersionToUse);
      Assert.fail("Construction should have failed");
    } catch (IllegalArgumentException e) {
      // expected. Nothing to do
    }

    long operationTimeMs = SystemTime.getInstance().milliseconds() + TestUtils.RANDOM.nextInt();
    int numResponseInfos = 5;
    int numMessagesInEachResponseInfo = 200;
    List<ReplicaMetadataResponseInfo> replicaMetadataResponseInfoList = new ArrayList<>();
    for (int j = 0; j < numResponseInfos; j++) {
      List<MessageInfo> messageInfoList = new ArrayList<MessageInfo>();
      int totalSizeOfAllMessages = 0;
      for (int i = 0; i < numMessagesInEachResponseInfo; i++) {
        int msgSize = TestUtils.RANDOM.nextInt(1000) + 1;
        short accountId = Utils.getRandomShort(TestUtils.RANDOM);
        short containerId = Utils.getRandomShort(TestUtils.RANDOM);
        BlobId id = new BlobId(CommonTestUtils.getCurrentBlobIdVersion(), BlobId.BlobIdType.NATIVE,
            ClusterMap.UNKNOWN_DATACENTER_ID, accountId, containerId,
            clusterMap.getWritablePartitionIds(MockClusterMap.DEFAULT_PARTITION_CLASS).get(0), false,
            BlobId.BlobDataType.DATACHUNK);
        MessageInfo messageInfo =
            new MessageInfo(id, msgSize, false, false, true, Utils.Infinite_Time, null, accountId, containerId,
                operationTimeMs, (short) 1);
        messageInfoList.add(messageInfo);
        totalSizeOfAllMessages += msgSize;
      }
      ReplicaMetadataResponseInfo responseInfo = new ReplicaMetadataResponseInfo(
          clusterMap.getWritablePartitionIds(MockClusterMap.DEFAULT_PARTITION_CLASS).get(0), replicaType,
          new MockFindToken(0, 1000), messageInfoList, 1000, responseVersionToUse);
      Assert.assertEquals("Total size of messages not as expected", totalSizeOfAllMessages,
          responseInfo.getTotalSizeOfAllMessages());
      replicaMetadataResponseInfoList.add(responseInfo);
    }
    ReplicaMetadataResponse response =
        new ReplicaMetadataResponse(1234, "clientId", ServerErrorCode.NoError, replicaMetadataResponseInfoList,
            responseVersionToUse);
    requestStream = serAndPrepForRead(response, -1, false);
    ReplicaMetadataResponse deserializedReplicaMetadataResponse =
        ReplicaMetadataResponse.readFrom(requestStream, new MockFindTokenHelper(), clusterMap);
    Assert.assertEquals(deserializedReplicaMetadataResponse.getCorrelationId(), 1234);
    Assert.assertEquals(deserializedReplicaMetadataResponse.getError(), ServerErrorCode.NoError);
    Assert.assertEquals("ReplicaMetadataResponse list size mismatch ", numResponseInfos,
        deserializedReplicaMetadataResponse.getReplicaMetadataResponseInfoList().size());
    for (int j = 0; j < replicaMetadataResponseInfoList.size(); j++) {
      ReplicaMetadataResponseInfo originalMetadataResponse = replicaMetadataResponseInfoList.get(j);
      ReplicaMetadataResponseInfo replicaMetadataResponseInfo =
          deserializedReplicaMetadataResponse.getReplicaMetadataResponseInfoList().get(j);
      Assert.assertEquals("MsgInfo list size in ReplicaMetadataResponse mismatch ", numMessagesInEachResponseInfo,
          replicaMetadataResponseInfo.getMessageInfoList().size());
      Assert.assertEquals("Total size of messages not as expected",
          originalMetadataResponse.getTotalSizeOfAllMessages(),
          replicaMetadataResponseInfo.getTotalSizeOfAllMessages());
      List<MessageInfo> deserializedMsgInfoList = replicaMetadataResponseInfo.getMessageInfoList();
      for (int i = 0; i < originalMetadataResponse.getMessageInfoList().size(); i++) {
        MessageInfo originalMsgInfo = originalMetadataResponse.getMessageInfoList().get(i);
        MessageInfo msgInfo = deserializedMsgInfoList.get(i);
        Assert.assertEquals("MsgInfo size mismatch ", originalMsgInfo.getSize(), msgInfo.getSize());
        Assert.assertEquals("MsgInfo key mismatch ", originalMsgInfo.getStoreKey(), msgInfo.getStoreKey());
        Assert.assertEquals("MsgInfo expiration value mismatch ", Utils.Infinite_Time, msgInfo.getExpirationTimeInMs());
        if (response.getVersionId() >= ReplicaMetadataResponse.REPLICA_METADATA_RESPONSE_VERSION_V_3) {
          Assert.assertEquals("AccountId mismatch ", originalMsgInfo.getAccountId(), msgInfo.getAccountId());
          Assert.assertEquals("ContainerId mismatch ", originalMsgInfo.getContainerId(), msgInfo.getContainerId());
          Assert.assertEquals("OperationTime mismatch ", operationTimeMs, msgInfo.getOperationTimeMs());
        } else {
          Assert.assertEquals("AccountId mismatch ", UNKNOWN_ACCOUNT_ID, msgInfo.getAccountId());
          Assert.assertEquals("ContainerId mismatch ", UNKNOWN_CONTAINER_ID, msgInfo.getContainerId());
          Assert.assertEquals("OperationTime mismatch ", Utils.Infinite_Time, msgInfo.getOperationTimeMs());
        }
        if (messageInfoToUse >= MessageInfoAndMetadataListSerde.VERSION_6) {
          Assert.assertTrue(msgInfo.isUndeleted());
          Assert.assertEquals("LifeVersion mismatch", (short) 1, msgInfo.getLifeVersion());
        } else {
          Assert.assertFalse(msgInfo.isUndeleted());
          Assert.assertEquals("LifeVersion mismatch", (short) 0, msgInfo.getLifeVersion());
        }
      }
    }
    response.release();
    // to ensure that the toString() representation does not go overboard, a random bound check is executed here.
    // a rough estimate is that each response info should contribute about 500 chars to the toString() representation
    int maxLength = 100 + numResponseInfos * 500;
    Assert.assertTrue("toString() representation longer than " + maxLength + " characters",
        response.toString().length() < maxLength);
    // test toString() of a ReplicaMetadataResponseInfo without any messages
    ReplicaMetadataResponseInfo responseInfo = new ReplicaMetadataResponseInfo(
        clusterMap.getWritablePartitionIds(MockClusterMap.DEFAULT_PARTITION_CLASS).get(0), replicaType,
        new MockFindToken(0, 1000), Collections.emptyList(), 1000, responseVersionToUse);
    Assert.assertTrue("Length of toString() should be > 0", responseInfo.toString().length() > 0);
    // test toString() of a ReplicaMetadataResponse without any ReplicaMetadataResponseInfo
    response = new ReplicaMetadataResponse(1234, "clientId", ServerErrorCode.NoError, Collections.emptyList(),
        responseVersionToUse);
    Assert.assertTrue("Length of toString() should be > 0", response.toString().length() > 0);
    response.release();
  }
Test the {@link StoreFileChunk#from} method.
@throws IOException
ambry-protocol/src/test/java/com/github/ambry/protocol/RequestResponseTest.java