@Test
  public void testCompaction() throws Exception {
    cleanup();

    int bucketCount = 20;
    PartitionId partitionId = new MockPartitionId(testPartition, MockClusterMap.DEFAULT_PARTITION_CLASS);

    // Upload blobs in various lifecycle states
    long now = System.currentTimeMillis();
    long creationTime = now - TimeUnit.DAYS.toMillis(7);
    for (int j = 0; j < bucketCount; j++) {
      Thread.sleep(20);
      logger.info("Uploading bucket {}", j);
      // Active blob
      BlobId blobId =
          new BlobId(BLOB_ID_V6, BlobIdType.NATIVE, dataCenterId, accountId, containerId, partitionId, false,
              BlobDataType.DATACHUNK);
      CloudBlobMetadata cloudBlobMetadata = new CloudBlobMetadata(blobId, creationTime, Utils.Infinite_Time, blobSize,
          CloudBlobMetadata.EncryptionOrigin.NONE);
      InputStream inputStream = getBlobInputStream(blobSize);
      assertTrue("Expected upload to return true",
          uploadBlobWithRetry(blobId, blobSize, cloudBlobMetadata, inputStream, cloudRequestAgent, azureDest));

      // Blob deleted before retention cutoff (should match)
      long timeOfDeath = now - TimeUnit.DAYS.toMillis(retentionPeriodDays + 1);
      blobId = new BlobId(BLOB_ID_V6, BlobIdType.NATIVE, dataCenterId, accountId, containerId, partitionId, false,
          BlobDataType.DATACHUNK);
      cloudBlobMetadata = new CloudBlobMetadata(blobId, creationTime, Utils.Infinite_Time, blobSize,
          CloudBlobMetadata.EncryptionOrigin.NONE);
      cloudBlobMetadata.setDeletionTime(timeOfDeath);
      assertTrue("Expected upload to return true",
          uploadBlobWithRetry(blobId, blobSize, cloudBlobMetadata, getBlobInputStream(blobSize), cloudRequestAgent,
              azureDest));

      // Blob expired before retention cutoff (should match)
      blobId = new BlobId(BLOB_ID_V6, BlobIdType.NATIVE, dataCenterId, accountId, containerId, partitionId, false,
          BlobDataType.DATACHUNK);
      cloudBlobMetadata =
          new CloudBlobMetadata(blobId, creationTime, timeOfDeath, blobSize, CloudBlobMetadata.EncryptionOrigin.NONE);
      assertTrue("Expected upload to return true",
          uploadBlobWithRetry(blobId, blobSize, cloudBlobMetadata, getBlobInputStream(blobSize), cloudRequestAgent,
              azureDest));

      // Blob deleted after retention cutoff
      timeOfDeath = now - TimeUnit.HOURS.toMillis(1);
      blobId = new BlobId(BLOB_ID_V6, BlobIdType.NATIVE, dataCenterId, accountId, containerId, partitionId, false,
          BlobDataType.DATACHUNK);
      cloudBlobMetadata = new CloudBlobMetadata(blobId, creationTime, Utils.Infinite_Time, blobSize,
          CloudBlobMetadata.EncryptionOrigin.NONE);
      cloudBlobMetadata.setDeletionTime(timeOfDeath);
      assertTrue("Expected upload to return true",
          uploadBlobWithRetry(blobId, blobSize, cloudBlobMetadata, getBlobInputStream(blobSize), cloudRequestAgent,
              azureDest));

      // Blob expired after retention cutoff
      blobId = new BlobId(BLOB_ID_V6, BlobIdType.NATIVE, dataCenterId, accountId, containerId, partitionId, false,
          BlobDataType.DATACHUNK);
      cloudBlobMetadata =
          new CloudBlobMetadata(blobId, creationTime, timeOfDeath, blobSize, CloudBlobMetadata.EncryptionOrigin.NONE);
      assertTrue("Expected upload to return true",
          uploadBlobWithRetry(blobId, blobSize, cloudBlobMetadata, getBlobInputStream(blobSize), cloudRequestAgent,
              azureDest));
    }

    // run getDeadBlobs query, should return 2 * bucketCount
    String partitionPath = String.valueOf(testPartition);
    int compactedCount = azureDest.compactPartition(partitionPath);
    assertEquals("Unexpected count compacted", 2 * bucketCount, compactedCount);
    cleanup();
  }
Test blob compaction.
@throws Exception on error
ambry-cloud/src/test/java/com/github/ambry/cloud/azure/AzureIntegrationTest.java