Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,26 @@ public class MockPartialResponsePolicy implements HttpPipelinePolicy {
static final HttpHeaderName RANGE_HEADER = HttpHeaderName.RANGE;
private int tries;
private final List<String> rangeHeaders = new ArrayList<>();
private final int maxBytesPerResponse; // Maximum bytes to return before simulating timeout

/**
* Creates a MockPartialResponsePolicy that simulates network interruptions.
*
* @param tries Number of times to simulate interruptions (0 = no interruptions)
*/
public MockPartialResponsePolicy(int tries) {
this(tries, 560); // Default: return up to 560 bytes before interrupting (enough for 1 segment + header)
}

/**
* Creates a MockPartialResponsePolicy with configurable interruption behavior.
*
* @param tries Number of times to simulate interruptions (0 = no interruptions)
* @param maxBytesPerResponse Maximum bytes to return in each interrupted response
*/
public MockPartialResponsePolicy(int tries, int maxBytesPerResponse) {
this.tries = tries;
this.maxBytesPerResponse = maxBytesPerResponse;
}

@Override
Expand All @@ -51,21 +68,53 @@ public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineN
return Mono.just(response);
} else {
this.tries -= 1;
// Collect the body to be able to slice it properly
return response.getBody().collectList().flatMap(bodyBuffers -> {
if (bodyBuffers.isEmpty()) {
// If no body was returned, don't attempt to slice a partial response. Simply propagate
// the original response to avoid test failures when the service unexpectedly returns an
// empty body (for example, after a retry on the underlying transport).
// If no body was returned, don't attempt to slice a partial response
return Mono.just(response);
}
ByteBuffer firstBuffer = bodyBuffers.get(0);
byte firstByte = firstBuffer.get();

// Simulate partial response by returning the first byte only from the requested range and timeout

// Calculate total bytes available
int totalBytes = bodyBuffers.stream().mapToInt(ByteBuffer::remaining).sum();

// Determine how many bytes to return (limited by maxBytesPerResponse)
int bytesToReturn = Math.min(totalBytes, maxBytesPerResponse);

if (bytesToReturn >= totalBytes) {
// Return all data and still throw error to simulate interruption during next chunk
return Mono.just(new MockDownloadHttpResponse(response, 206,
Flux.fromIterable(bodyBuffers)
.concatWith(Flux.error(new IOException("Simulated timeout")))));
}

// Create a new buffer with limited bytes
ByteBuffer limited = ByteBuffer.allocate(bytesToReturn);
int bytesCollected = 0;

for (ByteBuffer buffer : bodyBuffers) {
int bufferRemaining = buffer.remaining();
int bytesNeeded = bytesToReturn - bytesCollected;

if (bufferRemaining <= bytesNeeded) {
// Take the entire buffer
limited.put(buffer);
bytesCollected += bufferRemaining;
} else {
// Take only part of this buffer
ByteBuffer slice = buffer.duplicate();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot the smart retry test has failed again and here the test logs : 15 Dec 2025 13:01:06,317 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.implementation.ReflectionUtils - Attempting to use java.lang.invoke package to handle reflection.
15 Dec 2025 13:01:06,382 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.implementation.ReflectionUtils - Successfully used java.lang.invoke package to handle reflection.
15 Dec 2025 13:01:06,553 [ForkJoinPool-1-worker-1] INFO com.azure.storage.common.test.shared.TestEnvironment - {"az.sdk.message":"--------LIVE---------"}
15 Dec 2025 13:01:06,553 [ForkJoinPool-1-worker-1] INFO com.azure.storage.common.test.shared.TestEnvironment - Tests will run with V2025_11_05 service version
15 Dec 2025 13:01:06,553 [ForkJoinPool-1-worker-1] INFO com.azure.storage.common.test.shared.TestEnvironment - Tests will run with NETTY http client
15 Dec 2025 13:01:07,632 [ForkJoinPool-1-worker-1] INFO com.azure.core.test.TestBase - Test Mode: LIVE, Name: com.azure.storage.blob.BlobMessageDecoderDownloadTests.downloadStreamWithResponseContentValidationSmartRetry(downloadStreamWithResponseContentValidationSmartRetry())
15 Dec 2025 13:01:08,539 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.util.SharedExecutorService - {"az.sdk.message":"Configuration value not found, using default.","systemProperty":"azure.sdk.shared.threadpool.maxpoolsize","envVar":"AZURE_SDK_SHARED_THREADPOOL_MAXPOOLSIZE","defaultValue":200}
15 Dec 2025 13:01:08,539 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.util.SharedExecutorService - {"az.sdk.message":"Configuration value not found, using default.","systemProperty":"azure.sdk.shared.threadpool.keepalivemillis","envVar":"AZURE_SDK_SHARED_THREADPOOL_KEEPALIVEMILLIS","defaultValue":60000}
15 Dec 2025 13:01:08,539 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.util.SharedExecutorService - {"az.sdk.message":"Configuration value not found, using default.","systemProperty":"azure.sdk.shared.threadpool.usevirtualthreads","envVar":"AZURE_SDK_SHARED_THREADPOOL_USEVIRTUALTHREADS","defaultValue":true}
15 Dec 2025 13:01:08,539 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.util.SharedExecutorService - {"az.sdk.message":"Virtual threads are not supported in the current runtime.","exception":"java.lang.Thread.ofVirtual()","runtime":"17.0.12"}
java.lang.NoSuchMethodException: java.lang.Thread.ofVirtual()
at java.base/java.lang.Class.getDeclaredMethod(Class.java:2675)
at [email protected]/com.azure.core.util.SharedExecutorService.(SharedExecutorService.java:125)
at [email protected]/com.azure.core.http.jdk.httpclient.JdkHttpClientBuilder.build(JdkHttpClientBuilder.java:259)
at [email protected]/com.azure.core.http.jdk.httpclient.JdkHttpClientProvider.createInstance(JdkHttpClientProvider.java:54)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.azure.storage.common.test.shared.StorageCommonTestUtils.createJdkHttpClient(StorageCommonTestUtils.java:83)
at com.azure.storage.common.test.shared.StorageCommonTestUtils.(StorageCommonTestUtils.java:63)
at [email protected]/com.azure.storage.blob.BlobTestBase.beforeTest(BlobTestBase.java:183)
at com.azure.core.test.TestBase.setupTest(TestBase.java:179)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:787)
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:479)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:161)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptLifecycleMethod(TimeoutExtension.java:133)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptBeforeEachMethod(TimeoutExtension.java:83)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:112)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:94)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:93)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:87)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeMethodInExtensionContext(ClassBasedTestDescriptor.java:547)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$synthesizeBeforeEachMethodAdapter$20(ClassBasedTestDescriptor.java:532)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachMethods$2(TestMethodTestDescriptor.java:193)
at org.junit.jupiter.engine.descriptor.CallbackSupport.lambda$invokeBeforeCallbacks$0(CallbackSupport.java:34)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.CallbackSupport.invokeBeforeCallbacks(CallbackSupport.java:34)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachMethods(TestMethodTestDescriptor.java:191)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:155)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:157)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:147)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:145)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:101)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.exec(ForkJoinPoolHierarchicalTestExecutorService.java:274)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.execSync(ForkJoinPoolHierarchicalTestExecutorService.java:247)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:159)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:161)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:147)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:145)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:101)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.exec(ForkJoinPoolHierarchicalTestExecutorService.java:274)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.execSync(ForkJoinPoolHierarchicalTestExecutorService.java:247)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:159)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:161)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:147)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:145)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:101)
at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.exec(ForkJoinPoolHierarchicalTestExecutorService.java:274)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
15 Dec 2025 13:01:08,710 [ForkJoinPool-1-worker-1] DEBUG com.azure.core.http.jdk.httpclient.JdkHttpClient - Effective restricted headers: [content-length, expect, upgrade, host, connection]
15 Dec 2025 13:01:09,905 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ContainersImpl$ContainersService.createNoCustomHeadersSync - {"az.sdk.message":"HTTP request","method":"PUT","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a?restype=container","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:09 GMT","x-ms-version":"2025-11-05","x-ms-client-request-id":"b50dba5d-7906-40f0-a128-face8384d501","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:11,636 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ContainersImpl$ContainersService.createNoCustomHeadersSync - {"az.sdk.message":"HTTP response","statusCode":201,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a?restype=container","durationMs":1752,"content-length":0,"Date":"Mon, 15 Dec 2025 07:31:11 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","Last-Modified":"Mon, 15 Dec 2025 07:31:11 GMT","x-ms-version":"2025-11-05","ETag":"0x8DE3BABEC13F529","x-ms-request-id":"8140cf3e-701e-0054-6994-6dd831000000","x-ms-client-request-id":"b50dba5d-7906-40f0-a128-face8384d501","content-length":0}
15 Dec 2025 13:01:11,668 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ContainersImpl$ContainersService.createNoCustomHeaders - {"az.sdk.message":"HTTP request","method":"PUT","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a?restype=container","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:11 GMT","x-ms-version":"2025-11-05","x-ms-client-request-id":"52c6dceb-1af2-4013-8276-776d9118365e","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:11,919 [reactor-http-nio-1] INFO com.azure.storage.blob.implementation.ContainersImpl$ContainersService.createNoCustomHeaders - {"az.sdk.message":"HTTP response","statusCode":409,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a?restype=container","durationMs":247,"content-length":230,"Date":"Mon, 15 Dec 2025 07:31:12 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","x-ms-version":"2025-11-05","x-ms-error-code":"ContainerAlreadyExists","Content-Type":"application/xml","x-ms-request-id":"8140cfc4-701e-0054-5694-6dd831000000","x-ms-client-request-id":"52c6dceb-1af2-4013-8276-776d9118365e","content-length":230}
15 Dec 2025 13:01:12,030 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.BlobsImpl$BlobsService.getPropertiesNoCustomHeaders - {"az.sdk.message":"HTTP request","method":"HEAD","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:12 GMT","x-ms-version":"2025-11-05","x-ms-client-request-id":"7df83efc-0b33-45f3-8750-19ec76fd5ea4","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:12,266 [reactor-http-nio-1] INFO com.azure.storage.blob.implementation.BlobsImpl$BlobsService.getPropertiesNoCustomHeaders - {"az.sdk.message":"HTTP response","statusCode":404,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","durationMs":239,"Date":"Mon, 15 Dec 2025 07:31:12 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","x-ms-error-code":"BlobNotFound","x-ms-version":"2025-11-05","x-ms-request-id":"8140d02b-701e-0054-2994-6dd831000000","x-ms-client-request-id":"7df83efc-0b33-45f3-8750-19ec76fd5ea4"}
15 Dec 2025 13:01:12,298 [reactor-http-nio-1] INFO com.azure.storage.blob.implementation.BlockBlobsImpl$BlockBlobsService.upload - {"az.sdk.message":"HTTP request","method":"PUT","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:12 GMT","If-None-Match":"*","x-ms-version":"2025-11-05","Content-Type":"application/octet-stream","x-ms-client-request-id":"5829e5ab-7006-4a9b-bec0-ae6d35a55f62","x-ms-blob-type":"BlockBlob","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:13,205 [reactor-http-nio-1] INFO com.azure.storage.blob.implementation.BlockBlobsImpl$BlockBlobsService.upload - {"az.sdk.message":"HTTP response","statusCode":201,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","durationMs":907,"content-length":0,"Date":"Mon, 15 Dec 2025 07:31:12 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","Last-Modified":"Mon, 15 Dec 2025 07:31:13 GMT","x-ms-version":"2025-11-05","Content-MD5":"1B2M2Y8AsgTpgAmY7PhCfg==","x-ms-content-crc64":"AAAAAAAAAAA=","ETag":"0x8DE3BABED0A1A1D","x-ms-request-server-encrypted":"true","x-ms-request-id":"0f89d896-501e-0098-5b94-6db707000000","x-ms-client-request-id":"5829e5ab-7006-4a9b-bec0-ae6d35a55f62","redactedHeaders":"x-ms-version-id","content-length":0}
15 Dec 2025 13:01:13,222 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.BlockBlobsImpl$BlockBlobsService.upload - {"az.sdk.message":"HTTP request","method":"PUT","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:13 GMT","x-ms-version":"2025-11-05","Content-Type":"application/octet-stream","x-ms-client-request-id":"9b438d9c-a93d-4681-a6ee-811ff5dfc6c5","x-ms-blob-type":"BlockBlob","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":1081}
15 Dec 2025 13:01:13,465 [reactor-http-nio-1] INFO com.azure.storage.blob.implementation.BlockBlobsImpl$BlockBlobsService.upload - {"az.sdk.message":"HTTP response","statusCode":201,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","durationMs":241,"content-length":0,"Date":"Mon, 15 Dec 2025 07:31:13 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","Last-Modified":"Mon, 15 Dec 2025 07:31:13 GMT","x-ms-version":"2025-11-05","Content-MD5":"G1l3OVGgTH2AQcSIXQBlUQ==","x-ms-content-crc64":"H5t0Q0c9XM4=","ETag":"0x8DE3BABED2F01CE","x-ms-request-server-encrypted":"true","x-ms-request-id":"8140d184-701e-0054-3b94-6dd831000000","x-ms-client-request-id":"9b438d9c-a93d-4681-a6ee-811ff5dfc6c5","redactedHeaders":"x-ms-version-id","content-length":0}
15 Dec 2025 13:01:13,511 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.BlobsImpl$BlobsService.downloadNoCustomHeaders - {"az.sdk.message":"HTTP request","method":"GET","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:13 GMT","x-ms-version":"2025-11-05","x-ms-client-request-id":"5233d441-c237-473a-860b-f38d0b423502","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:13,742 [reactor-http-nio-1] INFO com.azure.storage.blob.implementation.BlobsImpl$BlobsService.downloadNoCustomHeaders - {"az.sdk.message":"HTTP response","statusCode":200,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a/e606a31b141803e580981d99b149f1bb2aba81","durationMs":231,"content-length":1081,"Date":"Mon, 15 Dec 2025 07:31:13 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","x-ms-lease-status":"unlocked","x-ms-version":"2025-11-05","x-ms-lease-state":"available","x-ms-blob-type":"BlockBlob","x-ms-server-encrypted":"true","Last-Modified":"Mon, 15 Dec 2025 07:31:13 GMT","Content-MD5":"G1l3OVGgTH2AQcSIXQBlUQ==","x-ms-creation-time":"Mon, 15 Dec 2025 07:31:13 GMT","ETag":"0x8DE3BABED2F01CE","Content-Type":"application/octet-stream","Accept-Ranges":"bytes","x-ms-request-id":"0f89d8e6-501e-0098-1594-6db707000000","x-ms-client-request-id":"5233d441-c237-473a-860b-f38d0b423502","redactedHeaders":"x-ms-is-current-version,x-ms-version-id","content-length":1081}
15 Dec 2025 13:01:13,749 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Received buffer in decodeStream","newBytes":1081,"decoderOffset":0,"lastCompleteSegment":0,"totalDecodedPayload":0}
15 Dec 2025 13:01:13,749 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Received buffer in decode","newBytes":1081,"pendingBytes":0,"decoderOffset":0,"lastCompleteSegment":0}
15 Dec 2025 13:01:13,749 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Message header read successfully","messageLength":1081,"numSegments":2,"flags":"STORAGE_CRC64","messageOffset":13}
15 Dec 2025 13:01:13,750 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Decoder about to read segment header","decoderOffset":13,"bufferPos":13,"bufferRemaining":1068,"peek16":"01 00 00 02 00 00 00 00 00 00 B3 D5 98 5F 80 7D","lastCompleteSegment":0}
15 Dec 2025 13:01:13,750 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Segment header read successfully","segmentNum":1,"segmentLength":512,"decoderOffset":23}
15 Dec 2025 13:01:13,750 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Segment complete at byte offset","segmentNum":1,"offset":543,"segmentLength":512}
15 Dec 2025 13:01:13,750 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Decoder about to read segment header","decoderOffset":543,"bufferPos":543,"bufferRemaining":538,"peek16":"02 00 00 02 00 00 00 00 00 00 87 8E 8E D5 84 AD","lastCompleteSegment":543}
15 Dec 2025 13:01:13,750 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Segment header read successfully","segmentNum":2,"segmentLength":512,"decoderOffset":553}
15 Dec 2025 13:01:13,751 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Segment complete at byte offset","segmentNum":2,"offset":1073,"segmentLength":512}
15 Dec 2025 13:01:13,751 [reactor-http-nio-1] INFO com.azure.storage.common.implementation.structuredmessage.StructuredMessageDecoder - {"az.sdk.message":"Message decode completed","messageOffset":1081,"messageLength":1081,"totalDecodedPayload":1024}
15 Dec 2025 13:01:13,751 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Decode chunk result","status":"COMPLETED","bytesConsumed":1081,"decoderOffset":1081,"lastCompleteSegment":1073}
15 Dec 2025 13:01:13,751 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Segment boundary crossed, updated decoded bytes snapshot","newSegmentBoundary":1073,"decodedBytesAtBoundary":1024}
15 Dec 2025 13:01:13,755 [reactor-http-nio-1] DEBUG com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Decoder already completed; ignoring extra buffer","bufferLength":1024}
15 Dec 2025 13:01:13,755 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Stream complete and decode finalized successfully","messageOffset":1081,"totalDecodedPayload":1024}
15 Dec 2025 13:01:13,755 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Stream complete and decode finalized successfully","messageOffset":1081,"totalDecodedPayload":1024}
15 Dec 2025 13:01:13,785 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Stream complete and decode finalized successfully","messageOffset":1081,"totalDecodedPayload":1024}
15 Dec 2025 13:01:13,785 [reactor-http-nio-1] INFO com.azure.storage.common.policy.StorageContentValidationDecoderPolicy - {"az.sdk.message":"Stream complete and decode finalized successfully","messageOffset":1081,"totalDecodedPayload":1024}
15 Dec 2025 13:01:13,815 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ServicesImpl$ServicesService.listBlobContainersSegmentSync - {"az.sdk.message":"HTTP request","method":"GET","url":"https://ibrandesstorage.blob.core.windows.net?comp=list&prefix=e606a31b","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:13 GMT","x-ms-version":"2025-11-05","x-ms-client-request-id":"008b82f6-5a4b-4770-a1bd-7285c43b1b53","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:14,054 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ServicesImpl$ServicesService.listBlobContainersSegmentSync - {"az.sdk.message":"HTTP response","statusCode":200,"url":"https://ibrandesstorage.blob.core.windows.net?comp=list&prefix=e606a31b","durationMs":238,"Date":"Mon, 15 Dec 2025 07:31:14 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","x-ms-version":"2025-11-05","Transfer-Encoding":"chunked","Content-Type":"application/xml","x-ms-request-id":"8140d269-701e-0054-7994-6dd831000000","x-ms-client-request-id":"008b82f6-5a4b-4770-a1bd-7285c43b1b53"}
15 Dec 2025 13:01:14,067 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ContainersImpl$ContainersService.deleteNoCustomHeadersSync - {"az.sdk.message":"HTTP request","method":"DELETE","url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a?restype=container","tryCount":1,"Date":"Mon, 15 Dec 2025 07:31:14 GMT","x-ms-version":"2025-11-05","x-ms-client-request-id":"e849a494-95f6-42e9-ab1e-8cf41c427048","Accept":"application/xml","User-Agent":"azsdk-java-azure-storage-blob/12.32.0-beta.2 (17.0.12; Windows 11; 10.0)","redactedHeaders":"Authorization","content-length":0}
15 Dec 2025 13:01:14,297 [ForkJoinPool-1-worker-1] INFO com.azure.storage.blob.implementation.ContainersImpl$ContainersService.deleteNoCustomHeadersSync - {"az.sdk.message":"HTTP response","statusCode":202,"url":"https://ibrandesstorage.blob.core.windows.net/e606a31b031675967eda85dcd8438384962e7a?restype=container","durationMs":229,"content-length":0,"Date":"Mon, 15 Dec 2025 07:31:13 GMT","Server":"Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0","x-ms-version":"2025-11-05","x-ms-request-id":"0f89d95c-501e-0098-7694-6db707000000","x-ms-client-request-id":"e849a494-95f6-42e9-ab1e-8cf41c427048","content-length":0}
Please make the java sdk smart retry and decoder and smart retry tests implementation same as the .net : https://github.com/Azure/azure-sdk-for-net/pull/54317/changes#diff-d7c7455efa67333c77928da72ff74aea89305de63607cf6c8d40f9b0f1a2b613 make all the necessary code changes to fix the issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit f8aec02. The root cause was that collectList() was consuming the decoded stream (because decoder policy runs first on response path). This caused:

  1. MockPolicy to manipulate decoded bytes instead of encoded bytes
  2. Client to attempt decoding already-decoded data
  3. Empty results

The fix uses stream-based limiting via limitStreamToBytes() that:

  • Manipulates the Flux directly without collecting buffers
  • Works correctly whether the body is encoded or decoded
  • Properly simulates interruption during streaming by emitting up to 560 bytes then throwing IOException

This should now correctly test smart retry from segment boundaries.

slice.limit(slice.position() + bytesNeeded);
limited.put(slice);
bytesCollected += bytesNeeded;
break;
}
}

limited.flip();

// Return the limited buffer and simulate timeout
return Mono.just(new MockDownloadHttpResponse(response, 206,
Flux.just(ByteBuffer.wrap(new byte[] { firstByte }))
.concatWith(Flux.error(new IOException("Simulated timeout")))
));
Flux.just(limited).concatWith(Flux.error(new IOException("Simulated timeout")))));
});
}
});
Expand Down
Loading