From 21c8af0a3b20c6815a7a80c885ec3ae5388bd4b2 Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 5 May 2026 20:08:18 -0400 Subject: [PATCH 1/8] add checks for response headers --- ...obContentValidationAsyncDownloadTests.java | 114 ++++++++---------- .../BlobContentValidationDownloadTests.java | 72 ++++++----- .../com/azure/storage/blob/BlobTestBase.java | 51 ++++++++ 3 files changed, 144 insertions(+), 93 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java index 38a96c2521a9..6293e84c31c6 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java @@ -67,11 +67,10 @@ public void downloadStreamWithResponseContentValidation() { BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - StepVerifier - .create(downloadClient.downloadStreamWithResponse(options) - .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) - .assertNext(result -> TestUtils.assertArraysEqual(data, result)) - .verifyComplete(); + StepVerifier.create(downloadClient.downloadStreamWithResponse(options).flatMap(r -> { + assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + return FluxUtil.collectBytesInByteBufferStream(r.getValue()); + })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -89,9 +88,10 @@ public void downloadContentWithResponseContentValidation() { BlobDownloadContentOptions options = new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - StepVerifier.create(downloadClient.downloadContentWithResponse(options)) - .assertNext(r -> TestUtils.assertArraysEqual(data, r.getValue().toBytes())) - .verifyComplete(); + StepVerifier.create(downloadClient.downloadContentWithResponse(options)).assertNext(r -> { + assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + TestUtils.assertArraysEqual(data, r.getValue().toBytes()); + }).verifyComplete(); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -120,14 +120,16 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong(4L * 1024 * 1024); + int blockSize = 4 * Constants.MB; + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - StepVerifier.create(downloadClient.downloadToFileWithResponse(options)) - .assertNext(r -> assertNotNull(r.getValue())) - .verifyComplete(); + StepVerifier.create(downloadClient.downloadToFileWithResponse(options)).assertNext(r -> { + assertStructuredMessageInitialDownloadResponseHeaders(r.getHeaders(), fileSize, blockSize); + assertNotNull(r.getValue()); + }).verifyComplete(); assertTrue(compareFiles(file, outFile, 0, fileSize)); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); @@ -157,40 +159,21 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong(4L * 1024 * 1024); + int blockSize = 4 * Constants.MB; + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - StepVerifier.create(downloadClient.downloadToFileWithResponse(options)) - .assertNext(r -> assertNotNull(r.getValue())) - .verifyComplete(); + StepVerifier.create(downloadClient.downloadToFileWithResponse(options)).assertNext(r -> { + assertStructuredMessageInitialDownloadResponseHeaders(r.getHeaders(), fileSize, blockSize); + assertNotNull(r.getValue()); + }).verifyComplete(); assertTrue(compareFiles(file, outFile, 0, fileSize)); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } - /** - * Range download without content validation works correctly. - */ - @Test - public void downloadStreamWithResponseContentValidationRange() { - byte[] randomData = getRandomByteArray(4 * Constants.KB); - Flux input = Flux.just(ByteBuffer.wrap(randomData)); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); - - BlobRange range = new BlobRange(0, 512L); - - StepVerifier.create(downloadClient.upload(input, null, true) - .then(downloadClient.downloadStreamWithResponse(range, null, null, false)) - .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))).assertNext(r -> { - assertNotNull(r); - assertEquals(512, r.length); - }).verifyComplete(); - assertFalse(hasOnlyStructuredMessageDownloadHeaders(recorded)); - } - /** * Default behavior: when no algorithm is specified, default is NONE (no validation). */ @@ -220,13 +203,13 @@ public void downloadStreamWithAuto() { BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); downloadClient.upload(BinaryData.fromBytes(data)).block(); - StepVerifier - .create(downloadClient - .downloadStreamWithResponse( - new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO)) - .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) - .assertNext(result -> TestUtils.assertArraysEqual(data, result)) - .verifyComplete(); + StepVerifier.create(downloadClient + .downloadStreamWithResponse( + new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO)) + .flatMap(r -> { + assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + return FluxUtil.collectBytesInByteBufferStream(r.getValue()); + })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -262,7 +245,10 @@ public void downloadContentWithAuto() { StepVerifier .create(downloadClient.downloadContentWithResponse( new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO))) - .assertNext(r -> TestUtils.assertArraysEqual(data, r.getValue().toBytes())) + .assertNext(r -> { + assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + TestUtils.assertArraysEqual(data, r.getValue().toBytes()); + }) .verifyComplete(); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -275,14 +261,13 @@ public void interruptAndVerifyProperRewind() { final int segmentSize = Constants.KB; byte[] randomData = getRandomByteArray(2 * segmentSize); List recorded = new CopyOnWriteArrayList<>(); + List recordedResponseHeaders = new CopyOnWriteArrayList<>(); BlobAsyncClient blobClient = createBlobAsyncClientWithRequestSniffer(recorded); int interruptPos = segmentSize + (2 * (segmentSize / 4)) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(1, interruptPos, blobClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy = (context, next) -> { - recorded.add(context.getHttpRequest().getHeaders()); - return next.process(); - }; + HttpPipelinePolicy sniffPolicy + = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), recorded, recordedResponseHeaders); blobClient.upload(Flux.just(ByteBuffer.wrap(randomData)), null, true).block(); @@ -291,19 +276,19 @@ public void interruptAndVerifyProperRewind() { DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(5); - StepVerifier - .create(downloadClient - .downloadStreamWithResponse(new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) - .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) - .doFinally( - signalType -> assertTrue(mockPolicy.getHits() > 0, "Mock interruption policy was not invoked")) - .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) - .assertNext(result -> TestUtils.assertArraysEqual(randomData, result)) - .verifyComplete(); + StepVerifier.create(downloadClient + .downloadStreamWithResponse(new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) + .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) + .doFinally(signalType -> assertTrue(mockPolicy.getHits() > 0, "Mock interruption policy was not invoked")) + .flatMap(r -> { + assertStructuredMessageResponseHeaders(r.getHeaders(), randomData.length); + return FluxUtil.collectBytesInByteBufferStream(r.getValue()); + })).assertNext(result -> TestUtils.assertArraysEqual(randomData, result)).verifyComplete(); assertEquals(0, mockPolicy.getTriesRemaining(), "Expected the configured interruption to be consumed"); assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); + assertStructuredMessageResponseHeaders(recordedResponseHeaders, randomData.length, 2); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -317,15 +302,14 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { final int dataSize = 4 * Constants.KB; byte[] randomData = getRandomByteArray(dataSize); List recorded = new CopyOnWriteArrayList<>(); + List recordedResponseHeaders = new CopyOnWriteArrayList<>(); BlobAsyncClient blobClient = createBlobAsyncClientWithRequestSniffer(recorded); int interruptPos = segmentSize + (3 * (8 * Constants.KB)) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(multipleInterrupts ? 2 : 1, interruptPos, blobClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy = (context, next) -> { - recorded.add(context.getHttpRequest().getHeaders()); - return next.process(); - }; + HttpPipelinePolicy sniffPolicy + = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), recorded, recordedResponseHeaders); blobClient.upload(Flux.just(ByteBuffer.wrap(randomData)), null, true).block(); @@ -337,10 +321,14 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { StepVerifier.create(downloadClient .downloadStreamWithResponse(new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) - .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))).assertNext(result -> { + .flatMap(r -> { + assertStructuredMessageResponseHeaders(r.getHeaders(), dataSize); + return FluxUtil.collectBytesInByteBufferStream(r.getValue()); + })).assertNext(result -> { assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); TestUtils.assertArraysEqual(randomData, result); }).verifyComplete(); + assertStructuredMessageResponseHeaders(recordedResponseHeaders, dataSize, 1); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java index 86b7f116a60d..3f0fcc4df222 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java @@ -4,10 +4,14 @@ package com.azure.storage.blob; import com.azure.core.http.HttpHeaders; +import com.azure.core.http.rest.Response; import com.azure.core.http.policy.HttpPipelinePolicy; import com.azure.core.test.utils.TestUtils; import com.azure.core.util.BinaryData; import com.azure.core.util.Context; +import com.azure.storage.blob.models.BlobDownloadContentResponse; +import com.azure.storage.blob.models.BlobDownloadResponse; +import com.azure.storage.blob.models.BlobProperties; import com.azure.storage.blob.models.BlobSeekableByteChannelReadResult; import com.azure.storage.blob.models.BlobRange; import com.azure.storage.blob.models.DownloadRetryOptions; @@ -70,10 +74,11 @@ public void downloadStreamWithResponseContentValidation() { client.upload(BinaryData.fromBytes(data)); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - client.downloadStreamWithResponse(outputStream, + BlobDownloadResponse response = client.downloadStreamWithResponse(outputStream, new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64), null, Context.NONE); + assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -89,14 +94,12 @@ public void downloadContentWithResponseContentValidation() { BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); - byte[] result - = client - .downloadContentWithResponse( - new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64), - null, Context.NONE) - .getValue() - .toBytes(); + BlobDownloadContentResponse response = client.downloadContentWithResponse( + new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64), null, + Context.NONE); + byte[] result = response.getValue().toBytes(); + assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); TestUtils.assertArraysEqual(data, result); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -126,12 +129,15 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong(4L * 1024 * 1024); + int blockSize = 4 * Constants.MB; + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - assertNotNull(client.downloadToFileWithResponse(options, null, Context.NONE).getValue()); + Response response = client.downloadToFileWithResponse(options, null, Context.NONE); + assertStructuredMessageInitialDownloadResponseHeaders(response.getHeaders(), fileSize, blockSize); + assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -160,12 +166,15 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong(4L * 1024 * 1024); + int blockSize = 4 * Constants.MB; + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - assertNotNull(client.downloadToFileWithResponse(options, null, Context.NONE).getValue()); + Response response = client.downloadToFileWithResponse(options, null, Context.NONE); + assertStructuredMessageInitialDownloadResponseHeaders(response.getHeaders(), fileSize, blockSize); + assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -221,8 +230,9 @@ public void downloadStreamWithAuto() { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO); - client.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + BlobDownloadResponse response = client.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -261,14 +271,12 @@ public void downloadContentWithAuto() { BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); - byte[] result - = client - .downloadContentWithResponse( - new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO), - null, Context.NONE) - .getValue() - .toBytes(); + BlobDownloadContentResponse response = client.downloadContentWithResponse( + new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO), null, + Context.NONE); + byte[] result = response.getValue().toBytes(); + assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); TestUtils.assertArraysEqual(data, result); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -281,6 +289,7 @@ public void interruptAndVerifyProperRewind() { final int segmentSize = Constants.KB; byte[] randomData = getRandomByteArray(2 * segmentSize); List recorded = new CopyOnWriteArrayList<>(); + List recordedResponseHeaders = new CopyOnWriteArrayList<>(); BlobClient uploadClient = createBlobClientWithRequestSniffer(recorded); uploadClient.upload(BinaryData.fromBytes(randomData)); @@ -288,10 +297,8 @@ public void interruptAndVerifyProperRewind() { int interruptPos = segmentSize + (2 * (segmentSize / 4)) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(1, interruptPos, uploadClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy = (context, next) -> { - recorded.add(context.getHttpRequest().getHeaders()); - return next.process(); - }; + HttpPipelinePolicy sniffPolicy + = getRequestAndResponseHeaderSniffer(uploadClient.getBlobUrl(), recorded, recordedResponseHeaders); BlobClient downloadClient = getBlobClient(ENVIRONMENT.getPrimaryAccount().getCredential(), uploadClient.getBlobUrl(), sniffPolicy, mockPolicy); @@ -300,12 +307,15 @@ public void interruptAndVerifyProperRewind() { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + BlobDownloadResponse response + = downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + assertStructuredMessageResponseHeaders(response.getHeaders(), randomData.length); TestUtils.assertArraysEqual(randomData, outputStream.toByteArray()); assertEquals(0, mockPolicy.getTriesRemaining(), "Expected the configured interruption to be consumed"); assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); + assertStructuredMessageResponseHeaders(recordedResponseHeaders, randomData.length, 2); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } @@ -319,6 +329,7 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { final int dataSize = 4 * Constants.KB; byte[] randomData = getRandomByteArray(dataSize); List recorded = new CopyOnWriteArrayList<>(); + List recordedResponseHeaders = new CopyOnWriteArrayList<>(); BlobClient uploadClient = createBlobClientWithRequestSniffer(recorded); uploadClient.upload(BinaryData.fromBytes(randomData)); @@ -326,10 +337,8 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { int interruptPos = segmentSize + (3 * (8 * Constants.KB)) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(multipleInterrupts ? 2 : 1, interruptPos, uploadClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy = (context, next) -> { - recorded.add(context.getHttpRequest().getHeaders()); - return next.process(); - }; + HttpPipelinePolicy sniffPolicy + = getRequestAndResponseHeaderSniffer(uploadClient.getBlobUrl(), recorded, recordedResponseHeaders); BlobClient downloadClient = getBlobClient(ENVIRONMENT.getPrimaryAccount().getCredential(), uploadClient.getBlobUrl(), sniffPolicy, mockPolicy); @@ -338,11 +347,14 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + BlobDownloadResponse response + = downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + assertStructuredMessageResponseHeaders(response.getHeaders(), dataSize); byte[] result = outputStream.toByteArray(); assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); TestUtils.assertArraysEqual(randomData, result); + assertStructuredMessageResponseHeaders(recordedResponseHeaders, dataSize, 1); assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index 514ff455fb90..195b5ede62a5 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -12,6 +12,9 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpPipelinePosition; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; import com.azure.core.http.policy.AddDatePolicy; @@ -104,6 +107,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Base class for Azure Storage Blob tests. @@ -1389,6 +1393,53 @@ protected static boolean hasOnlyStructuredMessageDownloadHeaders(List recordedResponseHeaders, + int unencodedContentLength, int minimumResponseCount) { + assertTrue(recordedResponseHeaders.size() >= minimumResponseCount, + "Expected at least " + minimumResponseCount + " GET response(s)"); + recordedResponseHeaders + .forEach(headers -> assertStructuredMessageResponseHeaders(headers, unencodedContentLength)); + } + + protected static void assertStructuredMessageInitialDownloadResponseHeaders(HttpHeaders headers, + int totalUnencodedContentLength, int blockSize) { + if (totalUnencodedContentLength > 0) { + assertStructuredMessageResponseHeaders(headers, Math.min(totalUnencodedContentLength, blockSize)); + } + } + + protected static HttpPipelinePolicy getRequestAndResponseHeaderSniffer(String targetUrlPrefix, + List recordedRequestHeaders, List recordedResponseHeaders) { + return new HttpPipelinePolicy() { + @Override + public HttpPipelinePosition getPipelinePosition() { + return HttpPipelinePosition.PER_RETRY; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + recordedRequestHeaders.add(context.getHttpRequest().getHeaders()); + return next.process().map(response -> { + if (response.getRequest().getHttpMethod() == HttpMethod.GET + && response.getRequest().getUrl().toString().startsWith(targetUrlPrefix)) { + recordedResponseHeaders.add(response.getHeaders()); + } + return response; + }); + } + }; + } + private static boolean hasStructuredMessageRequestHeaders(List recordedRequestHeaders, boolean requireStructuredContentLength) { if (recordedRequestHeaders == null || recordedRequestHeaders.isEmpty()) { From 26064eeaf70ea2fa17c1cc4a7a2e9bf65c5fdd1e Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 13:13:38 -0400 Subject: [PATCH 2/8] fix linting --- .../storage/blob/BlobContentValidationAsyncDownloadTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java index 6293e84c31c6..d1fcad55b904 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java @@ -8,7 +8,6 @@ import com.azure.core.test.utils.TestUtils; import com.azure.core.util.BinaryData; import com.azure.core.util.FluxUtil; -import com.azure.storage.blob.models.BlobRange; import com.azure.storage.blob.models.DownloadRetryOptions; import com.azure.storage.blob.options.BlobDownloadContentOptions; import com.azure.storage.blob.options.BlobDownloadStreamOptions; From 6073a33432c199888f67ae55ce40619bad75665a Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 18:58:11 -0400 Subject: [PATCH 3/8] refactor async, change messageDownloadRequestHeaders signatures --- ...obContentValidationAsyncDownloadTests.java | 220 +++++++++--------- .../BlobContentValidationDownloadTests.java | 75 +++--- .../com/azure/storage/blob/BlobTestBase.java | 113 ++++++--- 3 files changed, 233 insertions(+), 175 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java index d1fcad55b904..ef2ae683ffab 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java @@ -18,7 +18,6 @@ import com.azure.storage.common.implementation.contentvalidation.StorageCrc64Calculator; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.policy.MockPartialResponsePolicy; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -32,7 +31,6 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -45,11 +43,45 @@ */ public class BlobContentValidationAsyncDownloadTests extends BlobTestBase { private static final int TEN_MB = 10 * Constants.MB; + private static final int BLOCK_SIZE = 4 * Constants.MB; + private final List createdFiles = new ArrayList<>(); - @AfterEach - public void cleanup() { + private byte[] data; + private HttpHeaders recordedRequestHeaders; + private HttpHeaders recordedResponseHeaders; + private BlobAsyncClient blobClient; + private BlobAsyncClient downloadClient; + private File file; + private File outFile; + + @Override + public void beforeTest() { + super.beforeTest(); + data = null; + recordedRequestHeaders = new HttpHeaders(); + recordedResponseHeaders = new HttpHeaders(); + blobClient = null; + downloadClient = null; + } + + @Override + protected void afterTest() { createdFiles.forEach(File::delete); + createdFiles.clear(); + data = null; + recordedRequestHeaders = new HttpHeaders(); + recordedResponseHeaders = new HttpHeaders(); + blobClient = null; + downloadClient = null; + file = null; + outFile = null; + super.afterTest(); + } + + private void initializeBlobClient() { + blobClient = createBlobAsyncClientWithRequestSniffer(recordedRequestHeaders); + downloadClient = blobClient; } /** @@ -57,20 +89,18 @@ public void cleanup() { */ @Test public void downloadStreamWithResponseContentValidation() { - byte[] data = getRandomByteArray(TEN_MB); - - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(BinaryData.fromBytes(data)).block(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); StepVerifier.create(downloadClient.downloadStreamWithResponse(options).flatMap(r -> { - assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); return FluxUtil.collectBytesInByteBufferStream(r.getValue()); })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -78,20 +108,18 @@ public void downloadStreamWithResponseContentValidation() { */ @Test public void downloadContentWithResponseContentValidation() { - byte[] data = getRandomByteArray(TEN_MB); - - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(BinaryData.fromBytes(data)).block(); BlobDownloadContentOptions options = new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); StepVerifier.create(downloadClient.downloadContentWithResponse(options)).assertNext(r -> { - assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); TestUtils.assertArraysEqual(data, r.getValue().toBytes()); }).verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -106,32 +134,30 @@ public void downloadContentWithResponseContentValidation() { 8 * 1026 * 1024 + 10, // medium file not aligned to block }) public void downloadToFileWithResponseContentValidation(int fileSize) throws IOException { - File file = getRandomFile(fileSize); + file = getRandomFile(fileSize); file.deleteOnExit(); createdFiles.add(file); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + initializeBlobClient(); downloadClient.uploadFromFile(file.toPath().toString(), true).block(); - File outFile = new File(prefix + ".txt"); + outFile = new File(prefix + ".txt"); createdFiles.add(outFile); outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - int blockSize = 4 * Constants.MB; - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) BLOCK_SIZE); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); StepVerifier.create(downloadClient.downloadToFileWithResponse(options)).assertNext(r -> { - assertStructuredMessageInitialDownloadResponseHeaders(r.getHeaders(), fileSize, blockSize); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); assertNotNull(r.getValue()); }).verifyComplete(); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -145,32 +171,30 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE 50 * Constants.MB + 22 // large file not on MB boundary }) public void downloadToFileLargeWithResponseContentValidation(int fileSize) throws IOException { - File file = getRandomFile(fileSize); + file = getRandomFile(fileSize); file.deleteOnExit(); createdFiles.add(file); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + initializeBlobClient(); downloadClient.uploadFromFile(file.toPath().toString(), true).block(); - File outFile = new File(prefix + ".txt"); + outFile = new File(prefix + ".txt"); createdFiles.add(outFile); outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - int blockSize = 4 * Constants.MB; - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) BLOCK_SIZE); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); StepVerifier.create(downloadClient.downloadToFileWithResponse(options)).assertNext(r -> { - assertStructuredMessageInitialDownloadResponseHeaders(r.getHeaders(), fileSize, blockSize); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); assertNotNull(r.getValue()); }).verifyComplete(); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -178,9 +202,8 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw */ @Test public void downloadStreamDefaultAlgorithmIsNone() { - byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(Flux.just(ByteBuffer.wrap(data)), null, true).block(); StepVerifier.create(downloadClient.downloadStreamWithResponse(new BlobDownloadStreamOptions()) @@ -188,7 +211,7 @@ public void downloadStreamDefaultAlgorithmIsNone() { assertNotNull(result); assertEquals(data.length, result.length); }).verifyComplete(); - assertFalse(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -196,20 +219,18 @@ public void downloadStreamDefaultAlgorithmIsNone() { */ @Test public void downloadStreamWithAuto() { - byte[] data = getRandomByteArray(TEN_MB); - - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(BinaryData.fromBytes(data)).block(); StepVerifier.create(downloadClient .downloadStreamWithResponse( new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO)) .flatMap(r -> { - assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); return FluxUtil.collectBytesInByteBufferStream(r.getValue()); })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -217,9 +238,8 @@ public void downloadStreamWithAuto() { */ @Test public void downloadContentWithNone() { - byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(Flux.just(ByteBuffer.wrap(data)), null, true).block(); StepVerifier @@ -227,7 +247,7 @@ public void downloadContentWithNone() { new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.NONE))) .assertNext(r -> TestUtils.assertArraysEqual(data, r.getValue().toBytes())) .verifyComplete(); - assertFalse(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -235,21 +255,19 @@ public void downloadContentWithNone() { */ @Test public void downloadContentWithAuto() { - byte[] data = getRandomByteArray(TEN_MB); - - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(BinaryData.fromBytes(data)).block(); StepVerifier .create(downloadClient.downloadContentWithResponse( new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO))) .assertNext(r -> { - assertStructuredMessageResponseHeaders(r.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); TestUtils.assertArraysEqual(data, r.getValue().toBytes()); }) .verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -258,20 +276,18 @@ public void downloadContentWithAuto() { @Test public void interruptAndVerifyProperRewind() { final int segmentSize = Constants.KB; - byte[] randomData = getRandomByteArray(2 * segmentSize); - List recorded = new CopyOnWriteArrayList<>(); - List recordedResponseHeaders = new CopyOnWriteArrayList<>(); - BlobAsyncClient blobClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(2 * segmentSize); + initializeBlobClient(); int interruptPos = segmentSize + (2 * (segmentSize / 4)) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(1, interruptPos, blobClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy - = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), recorded, recordedResponseHeaders); + HttpPipelinePolicy sniffPolicy = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), + recordedRequestHeaders, recordedResponseHeaders); - blobClient.upload(Flux.just(ByteBuffer.wrap(randomData)), null, true).block(); + blobClient.upload(Flux.just(ByteBuffer.wrap(data)), null, true).block(); - BlobAsyncClient downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - blobClient.getBlobUrl(), sniffPolicy, mockPolicy); + downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), blobClient.getBlobUrl(), + sniffPolicy, mockPolicy); DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(5); @@ -280,15 +296,15 @@ public void interruptAndVerifyProperRewind() { .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) .doFinally(signalType -> assertTrue(mockPolicy.getHits() > 0, "Mock interruption policy was not invoked")) .flatMap(r -> { - assertStructuredMessageResponseHeaders(r.getHeaders(), randomData.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); return FluxUtil.collectBytesInByteBufferStream(r.getValue()); - })).assertNext(result -> TestUtils.assertArraysEqual(randomData, result)).verifyComplete(); + })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); assertEquals(0, mockPolicy.getTriesRemaining(), "Expected the configured interruption to be consumed"); assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); - assertStructuredMessageResponseHeaders(recordedResponseHeaders, randomData.length, 2); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -299,21 +315,19 @@ public void interruptAndVerifyProperRewind() { public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { final int segmentSize = 128 * Constants.KB; final int dataSize = 4 * Constants.KB; - byte[] randomData = getRandomByteArray(dataSize); - List recorded = new CopyOnWriteArrayList<>(); - List recordedResponseHeaders = new CopyOnWriteArrayList<>(); - BlobAsyncClient blobClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(dataSize); + initializeBlobClient(); int interruptPos = segmentSize + (3 * (8 * Constants.KB)) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(multipleInterrupts ? 2 : 1, interruptPos, blobClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy - = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), recorded, recordedResponseHeaders); + HttpPipelinePolicy sniffPolicy = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), + recordedRequestHeaders, recordedResponseHeaders); - blobClient.upload(Flux.just(ByteBuffer.wrap(randomData)), null, true).block(); + blobClient.upload(Flux.just(ByteBuffer.wrap(data)), null, true).block(); - BlobAsyncClient downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - blobClient.getBlobUrl(), sniffPolicy, mockPolicy); + downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), blobClient.getBlobUrl(), + sniffPolicy, mockPolicy); DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(10); @@ -321,14 +335,14 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { .downloadStreamWithResponse(new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) .flatMap(r -> { - assertStructuredMessageResponseHeaders(r.getHeaders(), dataSize); + assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); return FluxUtil.collectBytesInByteBufferStream(r.getValue()); })).assertNext(result -> { assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); - TestUtils.assertArraysEqual(randomData, result); + TestUtils.assertArraysEqual(data, result); }).verifyComplete(); - assertStructuredMessageResponseHeaders(recordedResponseHeaders, dataSize, 1); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -336,10 +350,8 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { */ @Test public void structuredMessageVerifiesDecodedCrc64DownloadStreaming() { - byte[] data = getRandomByteArray(TEN_MB); - - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient downloadClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); downloadClient.upload(BinaryData.fromBytes(data)).block(); long expectedCrc = StorageCrc64Calculator.compute(data, 0); @@ -355,7 +367,7 @@ public void structuredMessageVerifiesDecodedCrc64DownloadStreaming() { assertEquals(expectedCrc, actualCrc); }) .verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -364,21 +376,18 @@ public void structuredMessageVerifiesDecodedCrc64DownloadStreaming() { @Test public void interruptWithDataIntact() { final int segmentSize = Constants.KB; - byte[] randomData = getRandomByteArray(4 * segmentSize); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient blobClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(4 * segmentSize); + initializeBlobClient(); int interruptPos = segmentSize + (3 * 128) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(1, interruptPos, blobClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy = (context, next) -> { - recorded.add(context.getHttpRequest().getHeaders()); - return next.process(); - }; + HttpPipelinePolicy sniffPolicy = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), + recordedRequestHeaders, recordedResponseHeaders); - blobClient.upload(Flux.just(ByteBuffer.wrap(randomData)), null, true).block(); + blobClient.upload(Flux.just(ByteBuffer.wrap(data)), null, true).block(); - BlobAsyncClient downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - blobClient.getBlobUrl(), sniffPolicy, mockPolicy); + downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), blobClient.getBlobUrl(), + sniffPolicy, mockPolicy); DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(5); @@ -387,9 +396,9 @@ public void interruptWithDataIntact() { .downloadStreamWithResponse(new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) - .assertNext(result -> TestUtils.assertArraysEqual(randomData, result)) + .assertNext(result -> TestUtils.assertArraysEqual(data, result)) .verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -398,21 +407,18 @@ public void interruptWithDataIntact() { @Test public void interruptMultipleTimesWithDataIntact() { final int segmentSize = Constants.KB; - byte[] randomData = getRandomByteArray(4 * segmentSize); - List recorded = new CopyOnWriteArrayList<>(); - BlobAsyncClient blobClient = createBlobAsyncClientWithRequestSniffer(recorded); + data = getRandomByteArray(4 * segmentSize); + initializeBlobClient(); int interruptPos = segmentSize + (3 * 128) + 10; MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(3, interruptPos, blobClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy = (context, next) -> { - recorded.add(context.getHttpRequest().getHeaders()); - return next.process(); - }; + HttpPipelinePolicy sniffPolicy = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), + recordedRequestHeaders, recordedResponseHeaders); - blobClient.upload(Flux.just(ByteBuffer.wrap(randomData)), null, true).block(); + blobClient.upload(Flux.just(ByteBuffer.wrap(data)), null, true).block(); - BlobAsyncClient downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - blobClient.getBlobUrl(), sniffPolicy, mockPolicy); + downloadClient = getBlobAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), blobClient.getBlobUrl(), + sniffPolicy, mockPolicy); DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(10); @@ -421,9 +427,9 @@ public void interruptMultipleTimesWithDataIntact() { .downloadStreamWithResponse(new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64)) .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) - .assertNext(result -> TestUtils.assertArraysEqual(randomData, result)) + .assertNext(result -> TestUtils.assertArraysEqual(data, result)) .verifyComplete(); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java index 3f0fcc4df222..14be76c612f9 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java @@ -69,7 +69,7 @@ public void cleanup() { public void downloadStreamWithResponseContentValidation() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -78,9 +78,9 @@ public void downloadStreamWithResponseContentValidation() { new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64), null, Context.NONE); - assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -90,7 +90,7 @@ public void downloadStreamWithResponseContentValidation() { public void downloadContentWithResponseContentValidation() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -99,9 +99,9 @@ public void downloadContentWithResponseContentValidation() { Context.NONE); byte[] result = response.getValue().toBytes(); - assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, result); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -120,7 +120,7 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE file.deleteOnExit(); createdFiles.add(file); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.uploadFromFile(file.toPath().toString(), true); @@ -139,7 +139,7 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE assertStructuredMessageInitialDownloadResponseHeaders(response.getHeaders(), fileSize, blockSize); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -157,7 +157,7 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw file.deleteOnExit(); createdFiles.add(file); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.uploadFromFile(file.toPath().toString(), true); @@ -176,7 +176,7 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw assertStructuredMessageInitialDownloadResponseHeaders(response.getHeaders(), fileSize, blockSize); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -186,7 +186,7 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw public void downloadStreamWithResponseContentValidationRange() { byte[] randomData = getRandomByteArray(4 * Constants.KB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(randomData)); @@ -195,7 +195,7 @@ public void downloadStreamWithResponseContentValidationRange() { client.downloadStreamWithResponse(outputStream, options, null, Context.NONE); assertEquals(512, outputStream.toByteArray().length); - assertFalse(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -205,7 +205,7 @@ public void downloadStreamWithResponseContentValidationRange() { public void downloadStreamDefaultAlgorithmIsNone() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -213,7 +213,7 @@ public void downloadStreamDefaultAlgorithmIsNone() { client.downloadStreamWithResponse(outputStream, new BlobDownloadStreamOptions(), null, Context.NONE); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertFalse(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -223,7 +223,7 @@ public void downloadStreamDefaultAlgorithmIsNone() { public void downloadStreamWithAuto() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -232,9 +232,9 @@ public void downloadStreamWithAuto() { = new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO); BlobDownloadResponse response = client.downloadStreamWithResponse(outputStream, options, null, Context.NONE); - assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -244,7 +244,7 @@ public void downloadStreamWithAuto() { public void downloadContentWithNone() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -257,7 +257,7 @@ public void downloadContentWithNone() { .toBytes(); TestUtils.assertArraysEqual(data, result); - assertFalse(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -267,7 +267,7 @@ public void downloadContentWithNone() { public void downloadContentWithAuto() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -276,9 +276,9 @@ public void downloadContentWithAuto() { Context.NONE); byte[] result = response.getValue().toBytes(); - assertStructuredMessageResponseHeaders(response.getHeaders(), data.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, result); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -288,7 +288,7 @@ public void downloadContentWithAuto() { public void interruptAndVerifyProperRewind() { final int segmentSize = Constants.KB; byte[] randomData = getRandomByteArray(2 * segmentSize); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); List recordedResponseHeaders = new CopyOnWriteArrayList<>(); BlobClient uploadClient = createBlobClientWithRequestSniffer(recorded); @@ -310,13 +310,15 @@ public void interruptAndVerifyProperRewind() { BlobDownloadResponse response = downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); - assertStructuredMessageResponseHeaders(response.getHeaders(), randomData.length); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(randomData, outputStream.toByteArray()); assertEquals(0, mockPolicy.getTriesRemaining(), "Expected the configured interruption to be consumed"); assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); - assertStructuredMessageResponseHeaders(recordedResponseHeaders, randomData.length, 2); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(recordedResponseHeaders.size() >= 2, + "Expected at least the initial response and one retry response"); + assertTrue(recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -328,7 +330,7 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { final int segmentSize = 128 * Constants.KB; final int dataSize = 4 * Constants.KB; byte[] randomData = getRandomByteArray(dataSize); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); List recordedResponseHeaders = new CopyOnWriteArrayList<>(); BlobClient uploadClient = createBlobClientWithRequestSniffer(recorded); @@ -350,12 +352,13 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { BlobDownloadResponse response = downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); - assertStructuredMessageResponseHeaders(response.getHeaders(), dataSize); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); byte[] result = outputStream.toByteArray(); assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); TestUtils.assertArraysEqual(randomData, result); - assertStructuredMessageResponseHeaders(recordedResponseHeaders, dataSize, 1); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(!recordedResponseHeaders.isEmpty()); + assertTrue(recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks @@ -364,7 +367,7 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { public void openInputStreamContentValidation() { byte[] data = getRandomByteArray(TEN_MB); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -373,7 +376,7 @@ public void openInputStreamContentValidation() { BlobInputStream inputStream = client.openInputStream(options, Context.NONE); TestUtils.assertArraysEqual(data, convertInputStreamToByteArray(inputStream)); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks @@ -385,7 +388,7 @@ public void openInputStreamRangeContentValidation() { int start = Constants.MB; int count = 3 * Constants.MB + 257; - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -397,7 +400,7 @@ public void openInputStreamRangeContentValidation() { byte[] downloadedRange = convertInputStreamToByteArray(inputStream); assertEquals(count, downloadedRange.length); TestUtils.assertArraysEqual(data, start, downloadedRange, 0, count); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } /** @@ -409,7 +412,7 @@ public void openSeekableByteChannelReadContentValidation(Integer streamBufferSiz int dataLength) throws IOException { byte[] data = getRandomByteArray(dataLength); - List recorded = new CopyOnWriteArrayList<>(); + HttpHeaders recorded = new HttpHeaders(); BlobClient client = createBlobClientWithRequestSniffer(recorded); client.upload(BinaryData.fromBytes(data)); @@ -435,7 +438,7 @@ public void openSeekableByteChannelReadContentValidation(Integer streamBufferSiz // and: "expected data downloaded" TestUtils.assertArraysEqual(data, downloadedData.toByteArray()); - assertTrue(hasOnlyStructuredMessageDownloadHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } static Stream channelReadDataSupplier() { diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index 195b5ede62a5..f8bfbd5da068 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -1386,40 +1386,54 @@ public static HttpPipelinePolicy getAddHeadersAndQueryPolicy(Map } protected static boolean hasOnlyStructuredMessageHeaders(List recordedRequestHeaders) { - return hasStructuredMessageRequestHeaders(recordedRequestHeaders, true); + return hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, true); } - protected static boolean hasOnlyStructuredMessageDownloadHeaders(List recordedRequestHeaders) { - return hasStructuredMessageRequestHeaders(recordedRequestHeaders, false); + protected static boolean hasStructuredMessageDownloadRequestHeaders(HttpHeaders recordedRequestHeaders) { + return hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false); } - protected static void assertStructuredMessageResponseHeaders(HttpHeaders headers, int unencodedContentLength) { - assertTrue(validateBasicHeaders(headers)); - assertEquals(StructuredMessageConstants.STRUCTURED_BODY_TYPE_VALUE, - headers.getValue(Constants.HeaderConstants.STRUCTURED_BODY_TYPE_HEADER_NAME)); - assertEquals(String.valueOf(unencodedContentLength), - headers.getValue(Constants.HeaderConstants.STRUCTURED_CONTENT_LENGTH_HEADER_NAME)); - assertEquals(String.valueOf(expectedStructuredMessageEncodedLength(unencodedContentLength)), - headers.getValue(HttpHeaderName.CONTENT_LENGTH)); + protected static boolean hasStructuredMessageDownloadRequestHeaders(HttpHeaders recordedRequestHeaders, + boolean requireStructuredContentLength) { + if (recordedRequestHeaders == null || recordedRequestHeaders.getSize() == 0) { + return false; + } + return hasStructuredMessageDownloadRequestHeaders(Collections.singletonList(recordedRequestHeaders), + requireStructuredContentLength); } - protected static void assertStructuredMessageResponseHeaders(List recordedResponseHeaders, - int unencodedContentLength, int minimumResponseCount) { - assertTrue(recordedResponseHeaders.size() >= minimumResponseCount, - "Expected at least " + minimumResponseCount + " GET response(s)"); - recordedResponseHeaders - .forEach(headers -> assertStructuredMessageResponseHeaders(headers, unencodedContentLength)); + protected static boolean hasStructuredMessageDownloadResponseHeaders(HttpHeaders headers) { + return validateBasicHeaders(headers) + && StructuredMessageConstants.STRUCTURED_BODY_TYPE_VALUE + .equalsIgnoreCase(headers.getValue(Constants.HeaderConstants.STRUCTURED_BODY_TYPE_HEADER_NAME)); } - protected static void assertStructuredMessageInitialDownloadResponseHeaders(HttpHeaders headers, - int totalUnencodedContentLength, int blockSize) { - if (totalUnencodedContentLength > 0) { - assertStructuredMessageResponseHeaders(headers, Math.min(totalUnencodedContentLength, blockSize)); - } + protected static HttpPipelinePolicy getRequestAndResponseHeaderSniffer(String targetUrlPrefix, + HttpHeaders recordedRequestHeaders, List recordedResponseHeaders) { + return new HttpPipelinePolicy() { + @Override + public HttpPipelinePosition getPipelinePosition() { + return HttpPipelinePosition.PER_RETRY; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + synchronized (recordedRequestHeaders) { + recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); + } + return next.process().map(response -> { + if (response.getRequest().getHttpMethod() == HttpMethod.GET + && response.getRequest().getUrl().toString().startsWith(targetUrlPrefix)) { + recordedResponseHeaders.add(response.getHeaders()); + } + return response; + }); + } + }; } protected static HttpPipelinePolicy getRequestAndResponseHeaderSniffer(String targetUrlPrefix, - List recordedRequestHeaders, List recordedResponseHeaders) { + HttpHeaders recordedRequestHeaders, HttpHeaders recordedResponseHeaders) { return new HttpPipelinePolicy() { @Override public HttpPipelinePosition getPipelinePosition() { @@ -1428,11 +1442,15 @@ public HttpPipelinePosition getPipelinePosition() { @Override public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { - recordedRequestHeaders.add(context.getHttpRequest().getHeaders()); + synchronized (recordedRequestHeaders) { + recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); + } return next.process().map(response -> { if (response.getRequest().getHttpMethod() == HttpMethod.GET && response.getRequest().getUrl().toString().startsWith(targetUrlPrefix)) { - recordedResponseHeaders.add(response.getHeaders()); + synchronized (recordedResponseHeaders) { + recordedResponseHeaders.setAllHttpHeaders(response.getHeaders()); + } } return response; }); @@ -1440,8 +1458,8 @@ public Mono process(HttpPipelineCallContext context, HttpPipelineN }; } - private static boolean hasStructuredMessageRequestHeaders(List recordedRequestHeaders, - boolean requireStructuredContentLength) { + protected static boolean hasStructuredMessageDownloadRequestHeaders(List recordedRequestHeaders, + boolean requireStructuredContentLength) { if (recordedRequestHeaders == null || recordedRequestHeaders.isEmpty()) { return false; } @@ -1481,6 +1499,7 @@ private static boolean hasStructuredMessageRequestHeaders(List reco }); } + protected static boolean hasOnlyCrc64Headers(List recordedRequestHeaders) { if (recordedRequestHeaders == null || recordedRequestHeaders.isEmpty()) { return false; @@ -1524,9 +1543,9 @@ protected static boolean hasNoContentValidationHeaders(List recorde } /** - * Creates a BlobClient that records all outgoing request headers into the supplied list. - * Each test should use its own list so tests can run concurrently. - */ + * Creates a BlobClient that records all outgoing request headers into the supplied list. + * Each test should use its own list so tests can run concurrently. + */ protected BlobClient createBlobClientWithRequestSniffer(List recordedRequestHeaders) { HttpPipelinePolicy sniffPolicy = (context, next) -> { recordedRequestHeaders.add(context.getHttpRequest().getHeaders()); @@ -1538,8 +1557,23 @@ protected BlobClient createBlobClientWithRequestSniffer(List record } /** - * Creates a BlobAsyncClient that records all outgoing request headers into the supplied list. - */ + * Creates a BlobClient that records outgoing request headers into the supplied headers. + */ + protected BlobClient createBlobClientWithRequestSniffer(HttpHeaders recordedRequestHeaders) { + HttpPipelinePolicy sniffPolicy = (context, next) -> { + synchronized (recordedRequestHeaders) { + recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); + } + return next.process(); + }; + BlobServiceClient serviceClient = getServiceClient(ENVIRONMENT.getPrimaryAccount().getCredential(), + ENVIRONMENT.getPrimaryAccount().getBlobEndpoint(), sniffPolicy); + return serviceClient.getBlobContainerClient(containerName).getBlobClient(generateBlobName()); + } + + /** + * Creates a BlobAsyncClient that records all outgoing request headers into the supplied list. + */ protected BlobAsyncClient createBlobAsyncClientWithRequestSniffer(List recordedRequestHeaders) { HttpPipelinePolicy sniffPolicy = (context, next) -> { recordedRequestHeaders.add(context.getHttpRequest().getHeaders()); @@ -1550,6 +1584,21 @@ protected BlobAsyncClient createBlobAsyncClientWithRequestSniffer(List { + synchronized (recordedRequestHeaders) { + recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); + } + return next.process(); + }; + BlobServiceAsyncClient serviceClient = getServiceAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), + ENVIRONMENT.getPrimaryAccount().getBlobEndpoint(), sniffPolicy); + return serviceClient.getBlobContainerAsyncClient(containerName).getBlobAsyncClient(generateBlobName()); + } + protected static long expectedStructuredMessageEncodedLength(int unencodedContentBytes) { return new StructuredMessageEncoder(unencodedContentBytes, StructuredMessageConstants.V1_DEFAULT_SEGMENT_CONTENT_LENGTH, StructuredMessageFlags.STORAGE_CRC64) From 9e21caa7688d9ce66584ac703837b16a7916ff7c Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 19:59:54 -0400 Subject: [PATCH 4/8] fix methods with wrong method names --- .../blob/BlobContentValidationDownloadTests.java | 10 ++++++---- .../test/java/com/azure/storage/blob/BlobTestBase.java | 5 ++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java index 14be76c612f9..77c8db827cfe 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java @@ -136,7 +136,7 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); Response response = client.downloadToFileWithResponse(options, null, Context.NONE); - assertStructuredMessageInitialDownloadResponseHeaders(response.getHeaders(), fileSize, blockSize); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); @@ -173,7 +173,7 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); Response response = client.downloadToFileWithResponse(options, null, Context.NONE); - assertStructuredMessageInitialDownloadResponseHeaders(response.getHeaders(), fileSize, blockSize); + assertTrue(hasStructuredMessageDownloadRequestHeaders(response.getHeaders())); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); @@ -317,7 +317,8 @@ public void interruptAndVerifyProperRewind() { "Expected at least the initial request and one retry with a range header"); assertTrue(recordedResponseHeaders.size() >= 2, "Expected at least the initial response and one retry response"); - assertTrue(recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); + assertTrue( + recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } @@ -357,7 +358,8 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); TestUtils.assertArraysEqual(randomData, result); assertTrue(!recordedResponseHeaders.isEmpty()); - assertTrue(recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); + assertTrue( + recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index f8bfbd5da068..79fa8296e3b5 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -1394,7 +1394,7 @@ protected static boolean hasStructuredMessageDownloadRequestHeaders(HttpHeaders } protected static boolean hasStructuredMessageDownloadRequestHeaders(HttpHeaders recordedRequestHeaders, - boolean requireStructuredContentLength) { + boolean requireStructuredContentLength) { if (recordedRequestHeaders == null || recordedRequestHeaders.getSize() == 0) { return false; } @@ -1459,7 +1459,7 @@ public Mono process(HttpPipelineCallContext context, HttpPipelineN } protected static boolean hasStructuredMessageDownloadRequestHeaders(List recordedRequestHeaders, - boolean requireStructuredContentLength) { + boolean requireStructuredContentLength) { if (recordedRequestHeaders == null || recordedRequestHeaders.isEmpty()) { return false; } @@ -1499,7 +1499,6 @@ protected static boolean hasStructuredMessageDownloadRequestHeaders(List recordedRequestHeaders) { if (recordedRequestHeaders == null || recordedRequestHeaders.isEmpty()) { return false; From d265f7a6586c81142830c8a8ed0434d84922f146 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 21:05:39 -0400 Subject: [PATCH 5/8] refactor sync --- .../BlobContentValidationDownloadTests.java | 262 +++++++++--------- 1 file changed, 133 insertions(+), 129 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java index 77c8db827cfe..01122cab33dd 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java @@ -26,7 +26,6 @@ import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.policy.MockPartialResponsePolicy; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -40,7 +39,6 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; import static com.azure.storage.blob.specialized.BlobSeekableByteChannelTests.copy; @@ -55,11 +53,48 @@ */ public class BlobContentValidationDownloadTests extends BlobTestBase { private static final int TEN_MB = 10 * Constants.MB; + private static final int BLOCK_SIZE = 4 * Constants.MB; + private final List createdFiles = new ArrayList<>(); - @AfterEach - public void cleanup() { + private byte[] data; + private HttpHeaders recordedRequestHeaders; + private HttpHeaders recordedResponseHeaders; + private BlobClient blobClient; + private BlobClient downloadClient; + private File file; + private File outFile; + private ByteArrayOutputStream outputStream; + + @Override + public void beforeTest() { + super.beforeTest(); + data = null; + recordedRequestHeaders = new HttpHeaders(); + recordedResponseHeaders = new HttpHeaders(); + blobClient = null; + downloadClient = null; + outputStream = null; + } + + @Override + protected void afterTest() { createdFiles.forEach(File::delete); + createdFiles.clear(); + data = null; + recordedRequestHeaders = new HttpHeaders(); + recordedResponseHeaders = new HttpHeaders(); + blobClient = null; + downloadClient = null; + file = null; + outFile = null; + outputStream = null; + super.afterTest(); + } + + private void initializeBlobClient() { + blobClient = createBlobClientWithRequestSniffer(recordedRequestHeaders); + downloadClient = blobClient; } /** @@ -67,20 +102,18 @@ public void cleanup() { */ @Test public void downloadStreamWithResponseContentValidation() { - byte[] data = getRandomByteArray(TEN_MB); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - BlobDownloadResponse response = client.downloadStreamWithResponse(outputStream, + outputStream = new ByteArrayOutputStream(); + BlobDownloadResponse response = downloadClient.downloadStreamWithResponse(outputStream, new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64), null, Context.NONE); assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -88,20 +121,18 @@ public void downloadStreamWithResponseContentValidation() { */ @Test public void downloadContentWithResponseContentValidation() { - byte[] data = getRandomByteArray(TEN_MB); - - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); - BlobDownloadContentResponse response = client.downloadContentWithResponse( + BlobDownloadContentResponse response = downloadClient.downloadContentWithResponse( new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64), null, Context.NONE); byte[] result = response.getValue().toBytes(); assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, result); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -116,30 +147,28 @@ public void downloadContentWithResponseContentValidation() { 8 * 1026 * 1024 + 10, // medium file not aligned to block }) public void downloadToFileWithResponseContentValidation(int fileSize) throws IOException { - File file = getRandomFile(fileSize); + file = getRandomFile(fileSize); file.deleteOnExit(); createdFiles.add(file); - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.uploadFromFile(file.toPath().toString(), true); + initializeBlobClient(); + blobClient.uploadFromFile(file.toPath().toString(), true); - File outFile = new File(prefix + ".txt"); + outFile = new File(prefix + ".txt"); createdFiles.add(outFile); outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - int blockSize = 4 * Constants.MB; - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) BLOCK_SIZE); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - Response response = client.downloadToFileWithResponse(options, null, Context.NONE); + Response response = downloadClient.downloadToFileWithResponse(options, null, Context.NONE); assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -153,30 +182,28 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE 50 * Constants.MB + 22 // large file not on MB boundary }) public void downloadToFileLargeWithResponseContentValidation(int fileSize) throws IOException { - File file = getRandomFile(fileSize); + file = getRandomFile(fileSize); file.deleteOnExit(); createdFiles.add(file); - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.uploadFromFile(file.toPath().toString(), true); + initializeBlobClient(); + blobClient.uploadFromFile(file.toPath().toString(), true); - File outFile = new File(prefix + ".txt"); + outFile = new File(prefix + ".txt"); createdFiles.add(outFile); outFile.deleteOnExit(); Files.deleteIfExists(outFile.toPath()); - int blockSize = 4 * Constants.MB; - ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) blockSize); + ParallelTransferOptions parallelOptions = new ParallelTransferOptions().setBlockSizeLong((long) BLOCK_SIZE); BlobDownloadToFileOptions options = new BlobDownloadToFileOptions(outFile.toPath().toString()).setParallelTransferOptions(parallelOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - Response response = client.downloadToFileWithResponse(options, null, Context.NONE); - assertTrue(hasStructuredMessageDownloadRequestHeaders(response.getHeaders())); + Response response = downloadClient.downloadToFileWithResponse(options, null, Context.NONE); + assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -184,18 +211,16 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw */ @Test public void downloadStreamWithResponseContentValidationRange() { - byte[] randomData = getRandomByteArray(4 * Constants.KB); + data = getRandomByteArray(4 * Constants.KB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(randomData)); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setRange(new BlobRange(0, 512L)); - client.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); assertEquals(512, outputStream.toByteArray().length); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -203,17 +228,15 @@ public void downloadStreamWithResponseContentValidationRange() { */ @Test public void downloadStreamDefaultAlgorithmIsNone() { - byte[] data = getRandomByteArray(TEN_MB); - - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - client.downloadStreamWithResponse(outputStream, new BlobDownloadStreamOptions(), null, Context.NONE); + outputStream = new ByteArrayOutputStream(); + downloadClient.downloadStreamWithResponse(outputStream, new BlobDownloadStreamOptions(), null, Context.NONE); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -221,20 +244,19 @@ public void downloadStreamDefaultAlgorithmIsNone() { */ @Test public void downloadStreamWithAuto() { - byte[] data = getRandomByteArray(TEN_MB); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO); - BlobDownloadResponse response = client.downloadStreamWithResponse(outputStream, options, null, Context.NONE); + BlobDownloadResponse response + = downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -242,14 +264,12 @@ public void downloadStreamWithAuto() { */ @Test public void downloadContentWithNone() { - byte[] data = getRandomByteArray(TEN_MB); - - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); byte[] result - = client + = downloadClient .downloadContentWithResponse( new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.NONE), null, Context.NONE) @@ -257,7 +277,7 @@ public void downloadContentWithNone() { .toBytes(); TestUtils.assertArraysEqual(data, result); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -265,20 +285,18 @@ public void downloadContentWithNone() { */ @Test public void downloadContentWithAuto() { - byte[] data = getRandomByteArray(TEN_MB); - - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); - BlobDownloadContentResponse response = client.downloadContentWithResponse( + BlobDownloadContentResponse response = downloadClient.downloadContentWithResponse( new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.AUTO), null, Context.NONE); byte[] result = response.getValue().toBytes(); assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, result); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -287,39 +305,33 @@ public void downloadContentWithAuto() { @Test public void interruptAndVerifyProperRewind() { final int segmentSize = Constants.KB; - byte[] randomData = getRandomByteArray(2 * segmentSize); - HttpHeaders recorded = new HttpHeaders(); - List recordedResponseHeaders = new CopyOnWriteArrayList<>(); + data = getRandomByteArray(2 * segmentSize); + initializeBlobClient(); - BlobClient uploadClient = createBlobClientWithRequestSniffer(recorded); - uploadClient.upload(BinaryData.fromBytes(randomData)); + blobClient.upload(BinaryData.fromBytes(data)); int interruptPos = segmentSize + (2 * (segmentSize / 4)) + 10; - MockPartialResponsePolicy mockPolicy - = new MockPartialResponsePolicy(1, interruptPos, uploadClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy - = getRequestAndResponseHeaderSniffer(uploadClient.getBlobUrl(), recorded, recordedResponseHeaders); + MockPartialResponsePolicy mockPolicy = new MockPartialResponsePolicy(1, interruptPos, blobClient.getBlobUrl()); + HttpPipelinePolicy sniffPolicy = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), + recordedRequestHeaders, recordedResponseHeaders); - BlobClient downloadClient = getBlobClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - uploadClient.getBlobUrl(), sniffPolicy, mockPolicy); + downloadClient = getBlobClient(ENVIRONMENT.getPrimaryAccount().getCredential(), blobClient.getBlobUrl(), + sniffPolicy, mockPolicy); DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(5); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); BlobDownloadResponse response = downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); - TestUtils.assertArraysEqual(randomData, outputStream.toByteArray()); + TestUtils.assertArraysEqual(data, outputStream.toByteArray()); assertEquals(0, mockPolicy.getTriesRemaining(), "Expected the configured interruption to be consumed"); assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); - assertTrue(recordedResponseHeaders.size() >= 2, - "Expected at least the initial response and one retry response"); - assertTrue( - recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -330,24 +342,22 @@ public void interruptAndVerifyProperRewind() { public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { final int segmentSize = 128 * Constants.KB; final int dataSize = 4 * Constants.KB; - byte[] randomData = getRandomByteArray(dataSize); - HttpHeaders recorded = new HttpHeaders(); - List recordedResponseHeaders = new CopyOnWriteArrayList<>(); + data = getRandomByteArray(dataSize); + initializeBlobClient(); - BlobClient uploadClient = createBlobClientWithRequestSniffer(recorded); - uploadClient.upload(BinaryData.fromBytes(randomData)); + blobClient.upload(BinaryData.fromBytes(data)); int interruptPos = segmentSize + (3 * (8 * Constants.KB)) + 10; MockPartialResponsePolicy mockPolicy - = new MockPartialResponsePolicy(multipleInterrupts ? 2 : 1, interruptPos, uploadClient.getBlobUrl()); - HttpPipelinePolicy sniffPolicy - = getRequestAndResponseHeaderSniffer(uploadClient.getBlobUrl(), recorded, recordedResponseHeaders); + = new MockPartialResponsePolicy(multipleInterrupts ? 2 : 1, interruptPos, blobClient.getBlobUrl()); + HttpPipelinePolicy sniffPolicy = getRequestAndResponseHeaderSniffer(blobClient.getBlobUrl(), + recordedRequestHeaders, recordedResponseHeaders); - BlobClient downloadClient = getBlobClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - uploadClient.getBlobUrl(), sniffPolicy, mockPolicy); + downloadClient = getBlobClient(ENVIRONMENT.getPrimaryAccount().getCredential(), blobClient.getBlobUrl(), + sniffPolicy, mockPolicy); DownloadRetryOptions retryOptions = new DownloadRetryOptions().setMaxRetryRequests(10); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream = new ByteArrayOutputStream(); BlobDownloadStreamOptions options = new BlobDownloadStreamOptions().setDownloadRetryOptions(retryOptions) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); BlobDownloadResponse response @@ -356,53 +366,48 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); byte[] result = outputStream.toByteArray(); assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); - TestUtils.assertArraysEqual(randomData, result); - assertTrue(!recordedResponseHeaders.isEmpty()); - assertTrue( - recordedResponseHeaders.stream().allMatch(BlobTestBase::hasStructuredMessageDownloadResponseHeaders)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + TestUtils.assertArraysEqual(data, result); + assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks @LiveOnly @Test public void openInputStreamContentValidation() { - byte[] data = getRandomByteArray(TEN_MB); - - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); + blobClient.upload(BinaryData.fromBytes(data)); BlobInputStreamOptions options = new BlobInputStreamOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64); - BlobInputStream inputStream = client.openInputStream(options, Context.NONE); + BlobInputStream inputStream = downloadClient.openInputStream(options, Context.NONE); TestUtils.assertArraysEqual(data, convertInputStreamToByteArray(inputStream)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks @LiveOnly @Test public void openInputStreamRangeContentValidation() { - byte[] data = getRandomByteArray(TEN_MB); + data = getRandomByteArray(TEN_MB); + initializeBlobClient(); int start = Constants.MB; int count = 3 * Constants.MB + 257; - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + blobClient.upload(BinaryData.fromBytes(data)); BlobInputStreamOptions options = new BlobInputStreamOptions().setRange(new BlobRange(start, (long) count)) .setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64) .setBlockSize(Constants.MB); - BlobInputStream inputStream = client.openInputStream(options, Context.NONE); + BlobInputStream inputStream = downloadClient.openInputStream(options, Context.NONE); byte[] downloadedRange = convertInputStreamToByteArray(inputStream); assertEquals(count, downloadedRange.length); TestUtils.assertArraysEqual(data, start, downloadedRange, 0, count); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } /** @@ -412,17 +417,16 @@ public void openInputStreamRangeContentValidation() { @MethodSource("channelReadDataSupplier") public void openSeekableByteChannelReadContentValidation(Integer streamBufferSize, int copyBufferSize, int dataLength) throws IOException { - byte[] data = getRandomByteArray(dataLength); + data = getRandomByteArray(dataLength); + initializeBlobClient(); - HttpHeaders recorded = new HttpHeaders(); - BlobClient client = createBlobClientWithRequestSniffer(recorded); - client.upload(BinaryData.fromBytes(data)); + blobClient.upload(BinaryData.fromBytes(data)); // when: "Channel initialized" BlobSeekableByteChannelReadOptions options = new BlobSeekableByteChannelReadOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.CRC64) .setReadSizeInBytes(streamBufferSize); - BlobSeekableByteChannelReadResult result = client.openSeekableByteChannelRead(options, Context.NONE); + BlobSeekableByteChannelReadResult result = downloadClient.openSeekableByteChannelRead(options, Context.NONE); SeekableByteChannel channel = result.getChannel(); // then: "Channel initialized to position zero" @@ -440,7 +444,7 @@ public void openSeekableByteChannelReadContentValidation(Integer streamBufferSiz // and: "expected data downloaded" TestUtils.assertArraysEqual(data, downloadedData.toByteArray()); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recorded)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); } static Stream channelReadDataSupplier() { From 538e62bf968fc4356cae86768e08bc6c52f1fca4 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 21:15:49 -0400 Subject: [PATCH 6/8] remove unnecessary helper in BlobTestBase --- .../test/java/com/azure/storage/blob/BlobTestBase.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index 79fa8296e3b5..e47917cb1db3 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -1390,16 +1390,10 @@ protected static boolean hasOnlyStructuredMessageHeaders(List recor } protected static boolean hasStructuredMessageDownloadRequestHeaders(HttpHeaders recordedRequestHeaders) { - return hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false); - } - - protected static boolean hasStructuredMessageDownloadRequestHeaders(HttpHeaders recordedRequestHeaders, - boolean requireStructuredContentLength) { if (recordedRequestHeaders == null || recordedRequestHeaders.getSize() == 0) { return false; } - return hasStructuredMessageDownloadRequestHeaders(Collections.singletonList(recordedRequestHeaders), - requireStructuredContentLength); + return hasStructuredMessageDownloadRequestHeaders(Collections.singletonList(recordedRequestHeaders), false); } protected static boolean hasStructuredMessageDownloadResponseHeaders(HttpHeaders headers) { From 4885110a01f52ae87beacd6801a779abc08fe3fa Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 21:36:24 -0400 Subject: [PATCH 7/8] reuse hasStructuredMessageDownloadRequestHeaders with List --- ...obContentValidationAsyncDownloadTests.java | 33 ++++----- .../BlobContentValidationDownloadTests.java | 35 +++++----- .../com/azure/storage/blob/BlobTestBase.java | 68 ++++--------------- 3 files changed, 49 insertions(+), 87 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java index ef2ae683ffab..3094ac49c5b8 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationAsyncDownloadTests.java @@ -31,6 +31,7 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -48,7 +49,7 @@ public class BlobContentValidationAsyncDownloadTests extends BlobTestBase { private final List createdFiles = new ArrayList<>(); private byte[] data; - private HttpHeaders recordedRequestHeaders; + private List recordedRequestHeaders; private HttpHeaders recordedResponseHeaders; private BlobAsyncClient blobClient; private BlobAsyncClient downloadClient; @@ -59,7 +60,7 @@ public class BlobContentValidationAsyncDownloadTests extends BlobTestBase { public void beforeTest() { super.beforeTest(); data = null; - recordedRequestHeaders = new HttpHeaders(); + recordedRequestHeaders = new CopyOnWriteArrayList<>(); recordedResponseHeaders = new HttpHeaders(); blobClient = null; downloadClient = null; @@ -70,7 +71,7 @@ protected void afterTest() { createdFiles.forEach(File::delete); createdFiles.clear(); data = null; - recordedRequestHeaders = new HttpHeaders(); + recordedRequestHeaders = new CopyOnWriteArrayList<>(); recordedResponseHeaders = new HttpHeaders(); blobClient = null; downloadClient = null; @@ -100,7 +101,7 @@ public void downloadStreamWithResponseContentValidation() { assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); return FluxUtil.collectBytesInByteBufferStream(r.getValue()); })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -119,7 +120,7 @@ public void downloadContentWithResponseContentValidation() { assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); TestUtils.assertArraysEqual(data, r.getValue().toBytes()); }).verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -157,7 +158,7 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE }).verifyComplete(); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -194,7 +195,7 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw }).verifyComplete(); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -211,7 +212,7 @@ public void downloadStreamDefaultAlgorithmIsNone() { assertNotNull(result); assertEquals(data.length, result.length); }).verifyComplete(); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -230,7 +231,7 @@ public void downloadStreamWithAuto() { assertTrue(hasStructuredMessageDownloadResponseHeaders(r.getHeaders())); return FluxUtil.collectBytesInByteBufferStream(r.getValue()); })).assertNext(result -> TestUtils.assertArraysEqual(data, result)).verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -247,7 +248,7 @@ public void downloadContentWithNone() { new BlobDownloadContentOptions().setContentValidationAlgorithm(ContentValidationAlgorithm.NONE))) .assertNext(r -> TestUtils.assertArraysEqual(data, r.getValue().toBytes())) .verifyComplete(); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -267,7 +268,7 @@ public void downloadContentWithAuto() { TestUtils.assertArraysEqual(data, r.getValue().toBytes()); }) .verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -304,7 +305,7 @@ public void interruptAndVerifyProperRewind() { assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -342,7 +343,7 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { TestUtils.assertArraysEqual(data, result); }).verifyComplete(); assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -367,7 +368,7 @@ public void structuredMessageVerifiesDecodedCrc64DownloadStreaming() { assertEquals(expectedCrc, actualCrc); }) .verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -398,7 +399,7 @@ public void interruptWithDataIntact() { .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) .assertNext(result -> TestUtils.assertArraysEqual(data, result)) .verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -429,7 +430,7 @@ public void interruptMultipleTimesWithDataIntact() { .flatMap(r -> FluxUtil.collectBytesInByteBufferStream(r.getValue()))) .assertNext(result -> TestUtils.assertArraysEqual(data, result)) .verifyComplete(); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java index 01122cab33dd..fd84ef02cbce 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobContentValidationDownloadTests.java @@ -39,6 +39,7 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; import static com.azure.storage.blob.specialized.BlobSeekableByteChannelTests.copy; @@ -58,7 +59,7 @@ public class BlobContentValidationDownloadTests extends BlobTestBase { private final List createdFiles = new ArrayList<>(); private byte[] data; - private HttpHeaders recordedRequestHeaders; + private List recordedRequestHeaders; private HttpHeaders recordedResponseHeaders; private BlobClient blobClient; private BlobClient downloadClient; @@ -70,7 +71,7 @@ public class BlobContentValidationDownloadTests extends BlobTestBase { public void beforeTest() { super.beforeTest(); data = null; - recordedRequestHeaders = new HttpHeaders(); + recordedRequestHeaders = new CopyOnWriteArrayList<>(); recordedResponseHeaders = new HttpHeaders(); blobClient = null; downloadClient = null; @@ -82,7 +83,7 @@ protected void afterTest() { createdFiles.forEach(File::delete); createdFiles.clear(); data = null; - recordedRequestHeaders = new HttpHeaders(); + recordedRequestHeaders = new CopyOnWriteArrayList<>(); recordedResponseHeaders = new HttpHeaders(); blobClient = null; downloadClient = null; @@ -113,7 +114,7 @@ public void downloadStreamWithResponseContentValidation() { assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -132,7 +133,7 @@ public void downloadContentWithResponseContentValidation() { assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, result); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -168,7 +169,7 @@ public void downloadToFileWithResponseContentValidation(int fileSize) throws IOE assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -203,7 +204,7 @@ public void downloadToFileLargeWithResponseContentValidation(int fileSize) throw assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); assertNotNull(response.getValue()); assertTrue(compareFiles(file, outFile, 0, fileSize)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -220,7 +221,7 @@ public void downloadStreamWithResponseContentValidationRange() { downloadClient.downloadStreamWithResponse(outputStream, options, null, Context.NONE); assertEquals(512, outputStream.toByteArray().length); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -236,7 +237,7 @@ public void downloadStreamDefaultAlgorithmIsNone() { downloadClient.downloadStreamWithResponse(outputStream, new BlobDownloadStreamOptions(), null, Context.NONE); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -256,7 +257,7 @@ public void downloadStreamWithAuto() { assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, outputStream.toByteArray()); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -277,7 +278,7 @@ public void downloadContentWithNone() { .toBytes(); TestUtils.assertArraysEqual(data, result); - assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertFalse(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -296,7 +297,7 @@ public void downloadContentWithAuto() { assertTrue(hasStructuredMessageDownloadResponseHeaders(response.getHeaders())); TestUtils.assertArraysEqual(data, result); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -331,7 +332,7 @@ public void interruptAndVerifyProperRewind() { assertTrue(mockPolicy.getRangeHeaders().size() >= 2, "Expected at least the initial request and one retry with a range header"); assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -368,7 +369,7 @@ public void interruptAndVerifyProperDecode(boolean multipleInterrupts) { assertEquals(dataSize, result.length, "Decoded data should have exactly " + dataSize + " bytes"); TestUtils.assertArraysEqual(data, result); assertTrue(hasStructuredMessageDownloadResponseHeaders(recordedResponseHeaders)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks @@ -384,7 +385,7 @@ public void openInputStreamContentValidation() { BlobInputStream inputStream = downloadClient.openInputStream(options, Context.NONE); TestUtils.assertArraysEqual(data, convertInputStreamToByteArray(inputStream)); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } // Only run this test in live mode as BlobOutputStream dynamically assigns blocks @@ -407,7 +408,7 @@ public void openInputStreamRangeContentValidation() { byte[] downloadedRange = convertInputStreamToByteArray(inputStream); assertEquals(count, downloadedRange.length); TestUtils.assertArraysEqual(data, start, downloadedRange, 0, count); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } /** @@ -444,7 +445,7 @@ public void openSeekableByteChannelReadContentValidation(Integer streamBufferSiz // and: "expected data downloaded" TestUtils.assertArraysEqual(data, downloadedData.toByteArray()); - assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders)); + assertTrue(hasStructuredMessageDownloadRequestHeaders(recordedRequestHeaders, false)); } static Stream channelReadDataSupplier() { diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index e47917cb1db3..55fc50861c00 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -100,6 +100,7 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -1403,31 +1404,22 @@ protected static boolean hasStructuredMessageDownloadResponseHeaders(HttpHeaders } protected static HttpPipelinePolicy getRequestAndResponseHeaderSniffer(String targetUrlPrefix, - HttpHeaders recordedRequestHeaders, List recordedResponseHeaders) { - return new HttpPipelinePolicy() { - @Override - public HttpPipelinePosition getPipelinePosition() { - return HttpPipelinePosition.PER_RETRY; - } - - @Override - public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { - synchronized (recordedRequestHeaders) { - recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); - } - return next.process().map(response -> { - if (response.getRequest().getHttpMethod() == HttpMethod.GET - && response.getRequest().getUrl().toString().startsWith(targetUrlPrefix)) { - recordedResponseHeaders.add(response.getHeaders()); - } - return response; - }); + HttpHeaders recordedRequestHeaders, HttpHeaders recordedResponseHeaders) { + return getRequestAndResponseHeaderSniffer(targetUrlPrefix, headers -> { + synchronized (recordedRequestHeaders) { + recordedRequestHeaders.setAllHttpHeaders(headers); } - }; + }, recordedResponseHeaders); } protected static HttpPipelinePolicy getRequestAndResponseHeaderSniffer(String targetUrlPrefix, - HttpHeaders recordedRequestHeaders, HttpHeaders recordedResponseHeaders) { + List recordedRequestHeaders, HttpHeaders recordedResponseHeaders) { + return getRequestAndResponseHeaderSniffer(targetUrlPrefix, recordedRequestHeaders::add, + recordedResponseHeaders); + } + + private static HttpPipelinePolicy getRequestAndResponseHeaderSniffer(String targetUrlPrefix, + Consumer requestRecorder, HttpHeaders recordedResponseHeaders) { return new HttpPipelinePolicy() { @Override public HttpPipelinePosition getPipelinePosition() { @@ -1436,9 +1428,7 @@ public HttpPipelinePosition getPipelinePosition() { @Override public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { - synchronized (recordedRequestHeaders) { - recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); - } + requestRecorder.accept(context.getHttpRequest().getHeaders()); return next.process().map(response -> { if (response.getRequest().getHttpMethod() == HttpMethod.GET && response.getRequest().getUrl().toString().startsWith(targetUrlPrefix)) { @@ -1549,21 +1539,6 @@ protected BlobClient createBlobClientWithRequestSniffer(List record return serviceClient.getBlobContainerClient(containerName).getBlobClient(generateBlobName()); } - /** - * Creates a BlobClient that records outgoing request headers into the supplied headers. - */ - protected BlobClient createBlobClientWithRequestSniffer(HttpHeaders recordedRequestHeaders) { - HttpPipelinePolicy sniffPolicy = (context, next) -> { - synchronized (recordedRequestHeaders) { - recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); - } - return next.process(); - }; - BlobServiceClient serviceClient = getServiceClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - ENVIRONMENT.getPrimaryAccount().getBlobEndpoint(), sniffPolicy); - return serviceClient.getBlobContainerClient(containerName).getBlobClient(generateBlobName()); - } - /** * Creates a BlobAsyncClient that records all outgoing request headers into the supplied list. */ @@ -1577,21 +1552,6 @@ protected BlobAsyncClient createBlobAsyncClientWithRequestSniffer(List { - synchronized (recordedRequestHeaders) { - recordedRequestHeaders.setAllHttpHeaders(context.getHttpRequest().getHeaders()); - } - return next.process(); - }; - BlobServiceAsyncClient serviceClient = getServiceAsyncClient(ENVIRONMENT.getPrimaryAccount().getCredential(), - ENVIRONMENT.getPrimaryAccount().getBlobEndpoint(), sniffPolicy); - return serviceClient.getBlobContainerAsyncClient(containerName).getBlobAsyncClient(generateBlobName()); - } - protected static long expectedStructuredMessageEncodedLength(int unencodedContentBytes) { return new StructuredMessageEncoder(unencodedContentBytes, StructuredMessageConstants.V1_DEFAULT_SEGMENT_CONTENT_LENGTH, StructuredMessageFlags.STORAGE_CRC64) From 62ce2d097f628e1dbd2fe98dcb02273e05835f7d Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 6 May 2026 22:05:42 -0400 Subject: [PATCH 8/8] remove unused imports --- .../src/test/java/com/azure/storage/blob/BlobTestBase.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index 55fc50861c00..8c8a9af0c746 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -108,7 +108,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /** * Base class for Azure Storage Blob tests.