private void stitchBlobAndVerify(byte[] requestBody, List<ChunkInfo> expectedStitchedChunks,
      ThrowingConsumer<ExecutionException> errorChecker) throws Exception {
    JSONObject headers = new JSONObject();
    FrontendRestRequestServiceTest.setAmbryHeadersForPut(headers, TestUtils.TTL_SECS, !REF_CONTAINER.isCacheable(),
        SERVICE_ID, CONTENT_TYPE, OWNER_ID, REF_ACCOUNT.getName(), REF_CONTAINER.getName(), null);
    RestRequest request = getRestRequest(headers, "/" + Operations.STITCH, requestBody);
    RestResponseChannel restResponseChannel = new MockRestResponseChannel();
    FutureResult<Void> future = new FutureResult<>();
    idConverterFactory.lastInput = null;
    postBlobHandler.handle(request, restResponseChannel, future::done);
    if (errorChecker == null) {
      future.get(TIMEOUT_SECS, TimeUnit.SECONDS);
      assertEquals("Unexpected converted ID", CONVERTED_ID, restResponseChannel.getHeader(RestUtils.Headers.LOCATION));
      InMemoryRouter.InMemoryBlob blob = router.getActiveBlobs().get(idConverterFactory.lastInput);
      assertEquals("List of chunks stitched does not match expected", expectedStitchedChunks, blob.getStitchedChunks());
      ByteArrayOutputStream expectedContent = new ByteArrayOutputStream();
      expectedStitchedChunks.stream()
          .map(chunkInfo -> router.getActiveBlobs().get(chunkInfo.getBlobId()).getBlob().array())
          .forEach(buf -> expectedContent.write(buf, 0, buf.length));
      assertEquals("Unexpected blob content stored", ByteBuffer.wrap(expectedContent.toByteArray()), blob.getBlob());
      //check actual size of stitched blob
      assertEquals("Unexpected blob size", Long.toString(getStitchedBlobSize(expectedStitchedChunks)),
          restResponseChannel.getHeader(RestUtils.Headers.BLOB_SIZE));
      if (reservedMetadataId == null) {
        assertTrue(ReservedMetadataIdMetrics.getReservedMetadataIdMetrics(
            metrics.getMetricRegistry()).noReservedMetadataForChunkedUploadCount.getCount() > 0);
      }
    } else {
      TestUtils.assertException(ExecutionException.class, () -> future.get(TIMEOUT_SECS, TimeUnit.SECONDS),
          errorChecker);
    }
  }
Make a stitch blob call using {@link PostBlobHandler} and verify the result of the operation.
@param requestBody the body of the stitch request to supply.
@param expectedStitchedChunks the expected chunks stitched together.
@param errorChecker if non-null, expect an exception to be thrown by the post flow and verify it using this
                    {@link ThrowingConsumer}.
@throws Exception
ambry-frontend/src/test/java/com/github/ambry/frontend/PostBlobHandlerTest.java