Skip to content

Commit eab99bf

Browse files
authored
Storage Content Validation - Verify Download Progress Listener Support (#49157)
* tests and blob client changes * addressing copilot comments * updating assets
1 parent e3c281c commit eab99bf

6 files changed

Lines changed: 108 additions & 34 deletions

File tree

sdk/storage/azure-storage-blob/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "java",
44
"TagPrefix": "java/storage/azure-storage-blob",
5-
"Tag": "java/storage/azure-storage-blob_021b9237c4"
5+
"Tag": "java/storage/azure-storage-blob_cb46d93569"
66
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,8 +1538,6 @@ Mono<Response<BlobProperties>> downloadToFileWithResponse(BlobDownloadToFileOpti
15381538
BlobRange finalRange = options.getRange() == null ? new BlobRange(0) : options.getRange();
15391539
final com.azure.storage.common.ParallelTransferOptions finalParallelTransferOptions
15401540
= ModelHelper.populateAndApplyDefaults(options.getParallelTransferOptions());
1541-
ContentValidationModeResolver.validateProgressWithContentValidation(finalParallelTransferOptions,
1542-
options.getContentValidationAlgorithm());
15431541
BlobRequestConditions finalConditions
15441542
= options.getRequestConditions() == null ? new BlobRequestConditions() : options.getRequestConditions();
15451543

sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.azure.core.test.utils.TestUtils;
99
import com.azure.core.util.BinaryData;
1010
import com.azure.core.util.FluxUtil;
11+
import com.azure.core.util.ProgressListener;
1112
import com.azure.storage.blob.models.BlobRange;
1213
import com.azure.storage.blob.models.DownloadRetryOptions;
1314
import com.azure.storage.blob.options.BlobDownloadContentOptions;
@@ -35,6 +36,7 @@
3536
import java.nio.file.Path;
3637
import java.util.List;
3738
import java.util.concurrent.CopyOnWriteArrayList;
39+
import java.util.concurrent.atomic.AtomicLong;
3840

3941
import static org.junit.jupiter.api.Assertions.assertEquals;
4042
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -446,4 +448,55 @@ public void interruptMultipleTimesWithDataIntact() {
446448
assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders));
447449
}
448450

451+
@Test
452+
public void verifyProgressListenerIsCompatibleWithContentValidation(@TempDir Path tempDir) throws IOException {
453+
byte[] data = getRandomByteArray(10 * Constants.MB);
454+
455+
BlobAsyncClient client = ccAsync.getBlobAsyncClient(generateBlobName());
456+
457+
MockProgressListener mockListenerWithContentVal = new MockProgressListener();
458+
MockProgressListener mockListenerWithoutContentVal = new MockProgressListener();
459+
460+
ParallelTransferOptions parallelOptionsWithContentVal
461+
= new ParallelTransferOptions().setProgressListener(mockListenerWithContentVal);
462+
ParallelTransferOptions parallelOptionsWithoutContentVal
463+
= new ParallelTransferOptions().setProgressListener(mockListenerWithoutContentVal);
464+
465+
File fileWithContentVal = createRandomFile(tempDir, 10 * Constants.MB);
466+
File outFileWithContentVal = tempDir.resolve("withcontentval.bin").toFile();
467+
File fileWithoutContentVal = createRandomFile(tempDir, 10 * Constants.MB);
468+
File outFileWithoutContentVal = tempDir.resolve("withoutcontentval.bin").toFile();
469+
470+
Files.deleteIfExists(outFileWithContentVal.toPath());
471+
Files.deleteIfExists(outFileWithoutContentVal.toPath());
472+
473+
BlobDownloadToFileOptions optionsWithContentVal
474+
= new BlobDownloadToFileOptions(outFileWithContentVal.getAbsolutePath())
475+
.setParallelTransferOptions(parallelOptionsWithContentVal)
476+
.setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64);
477+
BlobDownloadToFileOptions optionsWithoutContentVal
478+
= new BlobDownloadToFileOptions(outFileWithoutContentVal.getAbsolutePath())
479+
.setParallelTransferOptions(parallelOptionsWithoutContentVal);
480+
481+
StepVerifier.create(client.upload(BinaryData.fromBytes(data))
482+
.then(client.downloadToFileWithResponse(optionsWithContentVal))
483+
.then(client.downloadToFileWithResponse(optionsWithoutContentVal))).assertNext(ignored -> {
484+
long expectedBytes = data.length;
485+
assertEquals(expectedBytes, mockListenerWithContentVal.getReportedByteCount());
486+
assertEquals(expectedBytes, mockListenerWithoutContentVal.getReportedByteCount());
487+
}).verifyComplete();
488+
}
489+
490+
private static final class MockProgressListener implements ProgressListener {
491+
private final AtomicLong reportedByteCount = new AtomicLong(0L);
492+
493+
@Override
494+
public void handleProgress(long bytesTransferred) {
495+
this.reportedByteCount.updateAndGet(current -> Math.max(current, bytesTransferred));
496+
}
497+
498+
long getReportedByteCount() {
499+
return this.reportedByteCount.get();
500+
}
501+
}
449502
}

sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.azure.core.test.utils.TestUtils;
1010
import com.azure.core.util.BinaryData;
1111
import com.azure.core.util.Context;
12+
import com.azure.core.util.ProgressListener;
1213
import com.azure.storage.blob.models.BlobDownloadContentResponse;
1314
import com.azure.storage.blob.models.BlobDownloadResponse;
1415
import com.azure.storage.blob.models.BlobProperties;
@@ -42,6 +43,7 @@
4243
import java.nio.file.Path;
4344
import java.util.List;
4445
import java.util.concurrent.CopyOnWriteArrayList;
46+
import java.util.concurrent.atomic.AtomicLong;
4547
import java.util.stream.Stream;
4648

4749
import static com.azure.storage.blob.specialized.BlobSeekableByteChannelTests.copy;
@@ -419,6 +421,58 @@ public void openSeekableByteChannelReadContentValidation(Integer streamBufferSiz
419421
assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false));
420422
}
421423

424+
@Test
425+
public void verifyProgressListenerIsCompatibleWithContentValidation(@TempDir Path tempDir) throws IOException {
426+
byte[] data = getRandomByteArray(10 * Constants.MB);
427+
428+
BlobClient client = cc.getBlobClient(generateBlobName());
429+
client.upload(BinaryData.fromBytes(data));
430+
431+
MockProgressListener mockListenerWithContentVal = new MockProgressListener();
432+
MockProgressListener mockListenerWithoutContentVal = new MockProgressListener();
433+
434+
ParallelTransferOptions parallelOptionsWithContentVal
435+
= new ParallelTransferOptions().setProgressListener(mockListenerWithContentVal);
436+
ParallelTransferOptions parallelOptionsWithoutContentVal
437+
= new ParallelTransferOptions().setProgressListener(mockListenerWithoutContentVal);
438+
439+
File fileWithContentVal = createRandomFile(tempDir, 10 * Constants.MB);
440+
File outFileWithContentVal = tempDir.resolve("withcontentval.bin").toFile();
441+
File fileWithoutContentVal = createRandomFile(tempDir, 10 * Constants.MB);
442+
File outFileWithoutContentVal = tempDir.resolve("withoutcontentval.bin").toFile();
443+
444+
Files.deleteIfExists(outFileWithContentVal.toPath());
445+
Files.deleteIfExists(outFileWithoutContentVal.toPath());
446+
447+
BlobDownloadToFileOptions optionsWithContentVal
448+
= new BlobDownloadToFileOptions(outFileWithContentVal.getAbsolutePath())
449+
.setParallelTransferOptions(parallelOptionsWithContentVal)
450+
.setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64);
451+
BlobDownloadToFileOptions optionsWithoutContentVal
452+
= new BlobDownloadToFileOptions(outFileWithoutContentVal.getAbsolutePath())
453+
.setParallelTransferOptions(parallelOptionsWithoutContentVal);
454+
455+
client.downloadToFileWithResponse(optionsWithContentVal, null, Context.NONE);
456+
client.downloadToFileWithResponse(optionsWithoutContentVal, null, Context.NONE);
457+
458+
long expectedBytes = data.length;
459+
assertEquals(expectedBytes, mockListenerWithContentVal.getReportedByteCount());
460+
assertEquals(expectedBytes, mockListenerWithoutContentVal.getReportedByteCount());
461+
}
462+
463+
private static final class MockProgressListener implements ProgressListener {
464+
private final AtomicLong reportedByteCount = new AtomicLong(0L);
465+
466+
@Override
467+
public void handleProgress(long bytesTransferred) {
468+
this.reportedByteCount.updateAndGet(current -> Math.max(current, bytesTransferred));
469+
}
470+
471+
long getReportedByteCount() {
472+
return this.reportedByteCount.get();
473+
}
474+
}
475+
422476
static Stream<Arguments> channelReadDataSupplier() {
423477
return Stream.of(Arguments.of(50, 40, Constants.KB), Arguments.of(Constants.KB + 50, 40, Constants.KB),
424478
Arguments.of(null, Constants.MB, TEN_MB));

sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/contentvalidation/ContentValidationModeResolver.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -151,22 +151,6 @@ public static Context addStructuredMessageDecodingToContext(Context context,
151151
return base.addData(STRUCTURED_MESSAGE_DECODING_CONTEXT_KEY, true);
152152
}
153153

154-
/**
155-
* Validates that parallel transfer progress reporting is not combined with CRC64/AUTO content validation.
156-
*
157-
* @param parallelTransferOptions May be {@code null}.
158-
* @param contentValidationAlgorithm Transfer validation algorithm from options.
159-
* @throws IllegalArgumentException if a progress listener is set and {@link #isContentValidationAlgorithmPresent} is true.
160-
*/
161-
public static void validateProgressWithContentValidation(ParallelTransferOptions parallelTransferOptions,
162-
ContentValidationAlgorithm contentValidationAlgorithm) {
163-
if (parallelTransferOptions == null) {
164-
return;
165-
}
166-
validateProgressWithContentValidation(parallelTransferOptions.getProgressListener(),
167-
contentValidationAlgorithm);
168-
}
169-
170154
/**
171155
* Validates that progress reporting is not combined with CRC64/AUTO content validation.
172156
*

sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/contentvalidation/ContentValidationModeResolverTests.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.azure.core.util.Context;
77
import com.azure.core.util.ProgressListener;
88
import com.azure.storage.common.ContentValidationAlgorithm;
9-
import com.azure.storage.common.ParallelTransferOptions;
109
import org.junit.jupiter.api.Test;
1110
import org.junit.jupiter.params.ParameterizedTest;
1211
import org.junit.jupiter.params.provider.Arguments;
@@ -209,12 +208,6 @@ public void validateProgressWithContentValidationPassesWhenNoneOrNullAlgorithm()
209208
ContentValidationAlgorithm.NONE));
210209
}
211210

212-
@Test
213-
public void validateProgressWithContentValidationPassesWhenParallelOptionsNull() {
214-
assertDoesNotThrow(() -> ContentValidationModeResolver
215-
.validateProgressWithContentValidation((ParallelTransferOptions) null, ContentValidationAlgorithm.CRC64));
216-
}
217-
218211
@Test
219212
public void validateProgressWithContentValidationThrowsForCrc64() {
220213
ProgressListener listener = l -> {
@@ -233,14 +226,6 @@ public void validateProgressWithContentValidationThrowsForAuto() {
233226
.validateProgressWithContentValidation(listener, ContentValidationAlgorithm.AUTO));
234227
}
235228

236-
@Test
237-
public void validateProgressWithContentValidationParallelOptionsDelegatesToListener() {
238-
ParallelTransferOptions opts = new ParallelTransferOptions().setProgressListener(l -> {
239-
});
240-
assertThrows(IllegalArgumentException.class, () -> ContentValidationModeResolver
241-
.validateProgressWithContentValidation(opts, ContentValidationAlgorithm.CRC64));
242-
}
243-
244229
@Test
245230
public void isCrc64OrAutoReflectsCrc64AndAutoOnly() {
246231
assertTrue(ContentValidationModeResolver.isCrc64OrAuto(ContentValidationAlgorithm.CRC64));

0 commit comments

Comments
 (0)