void checkOperationChains(List<OperationChain> opChains) throws Exception {
    Map<PartitionId, Integer> partitionCount = new HashMap<>();
    double blobsPut = 0;
    for (OperationChain opChain : opChains) {
      if (!opChain.latch.await(AWAIT_TIMEOUT, TimeUnit.SECONDS)) {
        Assert.fail("Timeout waiting for operation chain " + opChain.chainId + " to finish and it is stuck at "
            + opChain.opIndex + "the op:" + opChain.currentOpType + " the blob id: " + opChain.blobId);
      }
      synchronized (opChain.testFutures) {
        for (TestFuture testFuture : opChain.testFutures) {
          testFuture.check();
        }
      }
      Assert.assertEquals("opChain stopped in the middle.", 0, opChain.operations.size());
      if (opChain.blobId != null) {
        blobsPut++;
        PartitionId partitionId = new BlobId(opChain.blobId, clusterMap).getPartition();
        int count = partitionCount.getOrDefault(partitionId, 0);
        partitionCount.put(partitionId, count + 1);
      }
    }
  }
Await completion of all {@link OperationChain}s in the {@code opChains} list. For each chain, check the results
of each stage of the chain. Also check that the blobs put into the cluster are relatively balanced between
partitions (no more than 3 times expected number of blobs per partition).
@param opChains the {@link OperationChain}s to await and check.
@throws Exception
ambry-server/src/integration-test/java/com/github/ambry/server/RouterServerTestFramework.java