@Override
    public Future deleteBlobAndValidate(final String blobId, final RouterErrorCode expectedErrorCode,
        final Callback callback, final MetricsCollector metricsCollector) {
      final FutureResult futureResult = new FutureResult();
      try {
        final Long startTimeGetBlobInMs = SystemTime.getInstance().milliseconds();
        router.deleteBlob(null, blobId, null, new Callback<Void>() {
          @Override
          public void onCompletion(Void result, Exception exception) {
            long latencyPerBlob = SystemTime.getInstance().milliseconds() - startTimeGetBlobInMs;
            metricsCollector.updateLatency(latencyPerBlob);
            logger.trace(" Time taken to delete blob {} in ms {}", blobId, latencyPerBlob);
            final AtomicReference<Exception> exceptionToReturn = new AtomicReference<>();
            if (exception == null) {
              logger.trace("Deletion of {} succeeded. Issuing Get to confirm the deletion ", blobId);
              getBlobAndValidate(blobId, null, RouterErrorCode.BlobDeleted, new Callback<GetBlobResult>() {
                @Override
                public void onCompletion(GetBlobResult getBlobResult, Exception exception) {
                  if (getBlobResult != null) {
                    exceptionToReturn.set(new IllegalStateException(
                        "Get of a deleted blob " + blobId + " should have failed with " + RouterErrorCode.BlobDeleted));
                  } else {
                    if (exception != null) {
                      exceptionToReturn.set(exception);
                    }
                  }
                }
              }, null);
            } else {
              if (exception instanceof RouterException) {
                RouterException routerException = (RouterException) exception;
                if (expectedErrorCode != null) {
                  if (!expectedErrorCode.equals(routerException.getErrorCode())) {
                    exceptionToReturn.set(routerException);
                  }
                } else {
                  exceptionToReturn.set(routerException);
                }
              } else {
                exceptionToReturn.set(
                    new IllegalStateException("UnknownException thrown for deletion of " + blobId, exception));
              }
            }
            futureResult.done(null, exceptionToReturn.get());
            if (callback != null) {
              callback.onCompletion(null, exceptionToReturn.get());
            }
          }
        }, QUOTA_CHARGE_EVENT_LISTENER);
      } catch (Exception e) {
        futureResult.done(null, e);
        if (callback != null) {
          callback.onCompletion(null, e);
        }
      }
      return futureResult;
    }
{@inheritDoc}
Request to delete the blob from the server directly pertaining to the {@code blobId} passed in and verify that
the subsequent get fails with {@link RouterErrorCode#BlobDeleted}
@param blobId the blobId the of that blob that needs to be fetched
@param expectedErrorCode the expected error code for the Delete call
@param callback the {@link Callback} that will be called on completion
@param metricsCollector the {@link MetricsCollector} to collect and report metrics
ambry-tools/src/main/java/com/github/ambry/tools/admin/ConcurrencyTestTool.java