diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json
index e8388dbaa150..7aed1248ffa7 100644
--- a/sdk/storage/azure-storage-blob/assets.json
+++ b/sdk/storage/azure-storage-blob/assets.json
@@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "java",
"TagPrefix": "java/storage/azure-storage-blob",
- "Tag": "java/storage/azure-storage-blob_e4ae407bc2"
+ "Tag": "java/storage/azure-storage-blob_0c7e10b175"
}
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 51abad78209e..1af61ef87f7f 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
@@ -22,6 +22,7 @@
import com.azure.core.http.rest.Response;
import com.azure.core.test.TestMode;
import com.azure.core.test.TestProxyTestBase;
+import com.azure.core.test.http.MockHttpResponse;
import com.azure.core.test.models.CustomMatcher;
import com.azure.core.test.models.TestProxySanitizer;
import com.azure.core.test.models.TestProxySanitizerType;
@@ -37,7 +38,6 @@
import com.azure.identity.ChainedTokenCredentialBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.identity.EnvironmentCredentialBuilder;
-import com.azure.json.JsonProviders;
import com.azure.json.JsonSerializable;
import com.azure.json.JsonWriter;
import com.azure.storage.blob.models.BlobContainerItem;
@@ -68,7 +68,6 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -879,6 +878,9 @@ protected String generateShareName() {
return generateResourceName(entityNo++);
}
+ private HttpPipeline dataPlanePipeline;
+ private HttpHeaders genericHeaders;
+
protected String createFileAndDirectoryWithoutFileShareDependency(byte[] data, String shareName)
throws IOException {
String accountName = ENVIRONMENT.getPrimaryAccount().getName();
@@ -886,11 +888,8 @@ protected String createFileAndDirectoryWithoutFileShareDependency(byte[] data, S
BearerTokenAuthenticationPolicy credentialPolicyDataPlane = new BearerTokenAuthenticationPolicy(
getTokenCredential(ENVIRONMENT.getTestMode()), Constants.STORAGE_SCOPE);
- //create share through management plane
- createFileShareWithoutDependency(shareName);
-
//setup headers that will be used in every request
- HttpHeaders genericHeaders = new HttpHeaders().set(X_MS_VERSION, "2025-07-05")
+ genericHeaders = new HttpHeaders().set(X_MS_VERSION, "2025-07-05")
.set(HttpHeaderName.ACCEPT, "application/xml")
.set(HttpHeaderName.HOST, accountName + ".file.core.windows.net")
.set(HttpHeaderName.CONTENT_LENGTH, "0")
@@ -904,8 +903,15 @@ protected String createFileAndDirectoryWithoutFileShareDependency(byte[] data, S
policies.add(new RequestIdPolicy());
// create data plane pipeline
- HttpPipeline dataPlanePipeline
- = new HttpPipelineBuilder().policies(policies.toArray(new HttpPipelinePolicy[0])).build();
+ dataPlanePipeline = new HttpPipelineBuilder().policies(policies.toArray(new HttpPipelinePolicy[0])).build();
+
+ // create share through data plane pipeline
+ String shareUrl = String.format("https://%s.file.core.windows.net/%s?restype=share", accountName, shareName);
+
+ HttpResponse shareCreateResponse
+ = dataPlanePipeline.send(new HttpRequest(HttpMethod.PUT, new URL(shareUrl), genericHeaders)).block();
+ assertNotNull(shareCreateResponse);
+ assertEquals(201, shareCreateResponse.getStatusCode());
// create directory
String directoryName = generateBlobName();
@@ -945,48 +951,14 @@ protected String createFileAndDirectoryWithoutFileShareDependency(byte[] data, S
return fileUrl;
}
- protected void createFileShareWithoutDependency(String shareName) throws IOException {
- String shareID = getFileShareID(shareName);
- Body shareBody = new Body();
- shareBody.setId(shareID);
- shareBody.setName(shareName);
- shareBody.setType("Microsoft.Storage/storageAccounts/fileServices/shares");
-
- ByteArrayOutputStream shareJson = new ByteArrayOutputStream();
- try (JsonWriter jsonWriter = JsonProviders.createWriter(shareJson)) {
- shareBody.toJson(jsonWriter);
- }
- HttpResponse response
- = getManagementPlanePipeline().send(new HttpRequest(HttpMethod.PUT, new URL(getFileShareUri(shareID)),
- new HttpHeaders(), Flux.just(ByteBuffer.wrap(shareJson.toByteArray())))).block();
- assertNotNull(response);
- assertEquals(201, response.getStatusCode());
- }
-
protected void deleteFileShareWithoutDependency(String shareName) throws IOException {
- String shareID = getFileShareID(shareName);
- HttpResponse response = getManagementPlanePipeline()
- .send(new HttpRequest(HttpMethod.DELETE, new URL(getFileShareUri(shareID)), new HttpHeaders()))
- .block();
- assertNotNull(response);
- assertEquals(200, response.getStatusCode());
- }
-
- protected HttpPipeline getManagementPlanePipeline() {
- BearerTokenAuthenticationPolicy credentialPolicyManagementPlane = new BearerTokenAuthenticationPolicy(
- getTokenCredential(ENVIRONMENT.getTestMode()), "https://management.azure.com/.default");
- return new HttpPipelineBuilder().policies(credentialPolicyManagementPlane).build();
- }
+ String shareUrl = String.format("https://%s.file.core.windows.net/%s?restype=share",
+ ENVIRONMENT.getPrimaryAccount().getName(), shareName);
- protected String getFileShareID(String shareName) {
- return String.format(
- "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/"
- + "%s/fileServices/default/shares/%s",
- SUBSCRIPTION_ID, RESOURCE_GROUP_NAME, ENVIRONMENT.getPrimaryAccount().getName(), shareName);
- }
-
- protected String getFileShareUri(String fileShareID) {
- return "https://management.azure.com" + fileShareID + "?api-version=2024-01-01";
+ HttpResponse shareDeleteResponse
+ = dataPlanePipeline.send(new HttpRequest(HttpMethod.DELETE, new URL(shareUrl), genericHeaders)).block();
+ assertNotNull(shareDeleteResponse);
+ assertEquals(202, shareDeleteResponse.getStatusCode());
}
public static final class Body implements JsonSerializable
{
@@ -1073,7 +1045,7 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
}
}
- //todo: change the copy of this method in StorageCommonTestUtils to take in TestMode instead of interception manager
+ //todo isbr: change the copy of this method in StorageCommonTestUtils to take in TestMode instead of interception manager
protected static TokenCredential getTokenCredential(TestMode testMode) {
if (testMode == TestMode.RECORD) {
return new DefaultAzureCredentialBuilder().build();
@@ -1109,4 +1081,172 @@ protected static TokenCredential getTokenCredential(TestMode testMode) {
return new MockTokenCredential();
}
}
+
+ protected static final class ListBlobsWithTimeoutTestClient implements HttpClient {
+ private final boolean isAsync;
+
+ ListBlobsWithTimeoutTestClient(Boolean isAsync) {
+ this.isAsync = isAsync;
+ }
+
+ private HttpResponse response(HttpRequest request, String xml) {
+ HttpHeaders headers = new HttpHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/xml");
+ return new MockHttpResponse(request, 200, headers, xml.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private String buildFirstRequest(Boolean useDelimiter) {
+ String delimiterString = useDelimiter ? "/" : "";
+
+ return ""
+ + ""
+ + "3" + delimiterString + "" + "" + "blob1"
+ + "" + "" + "blob2" + "" + "" + "blob3" + ""
+ + "" + "MARKER--" + "";
+ }
+
+ private String buildSecondRequest(Boolean useDelimiter) {
+ String delimiterString = useDelimiter ? "/" : "";
+
+ return ""
+ + ""
+ + "MARKER--" + "3" + delimiterString + "" + ""
+ + "blob4" + "" + "" + "blob5" + "" + ""
+ + "" + "";
+ }
+
+ @Override
+ public Mono send(HttpRequest request) {
+ String url = request.getUrl().toString();
+ HttpResponse response;
+ int delay = isAsync ? 4 : 8;
+
+ if (url.contains("?restype=container&comp=list&maxresults=")) {
+ // flat first request
+ response = response(request, buildFirstRequest(false));
+ } else if (url.contains("?restype=container&comp=list&marker=")) {
+ // flat second request
+ response = response(request, buildSecondRequest(false));
+ } else if (url.contains("?restype=container&comp=list&delimiter=/&maxresults=")) {
+ // hierarchy first request
+ response = response(request, buildFirstRequest(true));
+ } else if (url.contains("?restype=container&comp=list&delimiter=/&marker=")) {
+ // hierarchy second request
+ response = response(request, buildSecondRequest(true));
+ } else {
+ // fallback
+ return Mono.just(new MockHttpResponse(request, 404));
+ }
+
+ return Mono.delay(Duration.ofSeconds(delay)).then(Mono.just(response));
+ }
+ }
+
+ protected static final class FindBlobsWithTimeoutClient implements HttpClient {
+ private final boolean isAsync;
+
+ FindBlobsWithTimeoutClient(Boolean isAsync) {
+ this.isAsync = isAsync;
+ }
+
+ private HttpResponse response(HttpRequest request, String xml) {
+ HttpHeaders headers = new HttpHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/xml");
+ return new MockHttpResponse(request, 200, headers, xml.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private String buildFirstRequest() {
+ return ""
+ + ""
+ + ""dummyKey"='dummyValue'" + "3"
+ + "" + "" + "blob1" + "foo" + ""
+ + "" + "" + "dummyKey" + "dummyValue" + "" + ""
+ + "" + "" + "" + "blob2" + "foo"
+ + "" + "" + "" + "dummyKey" + "dummyValue" + ""
+ + "" + "" + "" + "" + "blob3"
+ + "foo" + "" + "" + "" + "dummyKey"
+ + "dummyValue" + "" + "" + "" + "" + ""
+ + "MARKER-" + "";
+ }
+
+ private String buildSecondRequest() {
+ return ""
+ + ""
+ + "MARKER-" + ""dummyKey"='dummyValue'"
+ + "3" + "" + "" + "blob4"
+ + "foo" + "" + "" + "" + "dummyKey"
+ + "dummyValue" + "" + "" + "" + "" + ""
+ + "blob5" + "foo" + "" + "" + ""
+ + "dummyKey" + "dummyValue" + "" + "" + "" + ""
+ + "" + "" + "";
+ }
+
+ @Override
+ public Mono send(HttpRequest request) {
+ String url = request.getUrl().toString();
+ HttpResponse response;
+ int delay = isAsync ? 4 : 8;
+
+ if (url.contains("marker")) {
+ // second request
+ response = response(request, buildSecondRequest());
+ } else if (url.contains("?comp=blobs&where=%") || url.contains("?restype=container&comp=blobs&where=%")) {
+ // first request
+ response = response(request, buildFirstRequest());
+ } else {
+ // fallback
+ return Mono.just(new MockHttpResponse(request, 404));
+ }
+
+ return Mono.delay(Duration.ofSeconds(delay)).then(Mono.just(response));
+ }
+ }
+
+ protected static final class ListContainersWithTimeoutTestClient implements HttpClient {
+ private final boolean isAsync;
+
+ ListContainersWithTimeoutTestClient(Boolean isAsync) {
+ this.isAsync = isAsync;
+ }
+
+ private HttpResponse response(HttpRequest request, String xml) {
+ HttpHeaders headers = new HttpHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/xml");
+ return new MockHttpResponse(request, 200, headers, xml.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private String buildFirstRequest() {
+ return ""
+ + ""
+ + "3" + "" + "" + "container1"
+ + "" + "" + "container2" + "" + ""
+ + "container3" + "" + ""
+ + "/marker/marker" + "";
+ }
+
+ private String buildSecondRequest() {
+ return ""
+ + ""
+ + "/marker/marker" + "3" + "" + ""
+ + "container4" + "" + "" + "container5"
+ + "" + "" + "" + "";
+ }
+
+ @Override
+ public Mono send(HttpRequest request) {
+ String url = request.getUrl().toString();
+ HttpResponse response;
+ int delay = isAsync ? 4 : 8;
+
+ if (url.contains("?comp=list&maxresults=")) {
+ // flat first request
+ response = response(request, buildFirstRequest());
+ } else if (url.contains("?comp=list&marker=")) {
+ // flat second request
+ response = response(request, buildSecondRequest());
+ } else {
+ // fallback
+ return Mono.just(new MockHttpResponse(request, 404));
+ }
+
+ return Mono.delay(Duration.ofSeconds(delay)).then(Mono.just(response));
+ }
+ }
}
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerApiTests.java
index 83828fdd7f8d..1f3ea9d5bf0f 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerApiTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerApiTests.java
@@ -1070,38 +1070,43 @@ public void listBlobsFlatError() {
assertThrows(BlobStorageException.class, () -> cc.listBlobs().iterator().hasNext());
}
+ /*
+ * For listBlobsFlatWithTimeoutStillBackedByPagedStream and listBlobsHierWithTimeoutStillBackedByPagedStream:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@Test
public void listBlobsFlatWithTimeoutStillBackedByPagedStream() {
- int numBlobs = 5;
- int pageResults = 3;
-
- for (int i = 0; i < numBlobs; i++) {
- BlockBlobClient blob = cc.getBlobClient(generateBlobName()).getBlockBlobClient();
- blob.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize());
- }
-
- // when: "Consume results by page, then still have paging functionality"
- assertDoesNotThrow(
- () -> cc.listBlobs(new ListBlobsOptions().setMaxResultsPerPage(pageResults), Duration.ofSeconds(10))
+ BlobContainerClient containerClient
+ = new BlobContainerClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .containerName("foo")
+ .httpClient(new ListBlobsWithTimeoutTestClient(false))
+ .buildClient();
+
+ assertEquals(2,
+ containerClient.listBlobs(new ListBlobsOptions().setMaxResultsPerPage(3), Duration.ofSeconds(14))
.streamByPage()
.count());
}
@Test
public void listBlobsHierWithTimeoutStillBackedByPagedStream() {
- int numBlobs = 5;
- int pageResults = 3;
-
- for (int i = 0; i < numBlobs; i++) {
- BlockBlobClient blob = cc.getBlobClient(generateBlobName()).getBlockBlobClient();
- blob.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize());
- }
-
- // when: "Consume results by page, then still have paging functionality"
- assertDoesNotThrow(() -> cc
- .listBlobsByHierarchy("/", new ListBlobsOptions().setMaxResultsPerPage(pageResults), Duration.ofSeconds(10))
- .streamByPage()
- .count());
+ BlobContainerClient containerClient
+ = new BlobContainerClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .containerName("foo")
+ .httpClient(new ListBlobsWithTimeoutTestClient(false))
+ .buildClient();
+
+ assertEquals(2,
+ containerClient
+ .listBlobsByHierarchy("/", new ListBlobsOptions().setMaxResultsPerPage(3), Duration.ofSeconds(14))
+ .streamByPage()
+ .count());
}
/*
@@ -1656,26 +1661,28 @@ public void findBlobsError() {
assertThrows(BlobStorageException.class, () -> cc.findBlobsByTags("garbageTag").streamByPage().count());
}
- @SuppressWarnings("deprecation")
+ /*
+ * For findBlobsWithTimeoutStillBackedByPagedStream:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2021-04-10")
@Test
public void findBlobsWithTimeoutStillBackedByPagedStream() {
- int numBlobs = 5;
- int pageResults = 3;
- Map tags = Collections.singletonMap(tagKey, tagValue);
-
- for (int i = 0; i < numBlobs; i++) {
- cc.getBlobClient(generateBlobName())
- .uploadWithResponse(
- new BlobParallelUploadOptions(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())
- .setTags(tags),
- null, null);
- }
+ BlobContainerClient containerClient
+ = new BlobContainerClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .containerName("foo")
+ .httpClient(new FindBlobsWithTimeoutClient(false))
+ .buildClient();
- // when: "Consume results by page, still have paging functionality"
- assertDoesNotThrow(() -> cc.findBlobsByTags(
- new FindBlobsOptions(String.format("\"%s\"='%s'", tagKey, tagValue)).setMaxResultsPerPage(pageResults),
- Duration.ofSeconds(10), Context.NONE).streamByPage().count());
+ assertEquals(2,
+ containerClient.findBlobsByTags(
+ new FindBlobsOptions(String.format("\"%s\"='%s'", "dummyKey", "dummyValue")).setMaxResultsPerPage(3),
+ Duration.ofSeconds(14), Context.NONE).streamByPage().count());
}
@ParameterizedTest
@@ -1760,6 +1767,7 @@ public void createURLSpecialCharsDecoded(String name) {
}
@Test
+ @PlaybackOnly
public void rootExplicit() {
cc = primaryBlobServiceClient.getBlobContainerClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// create root container if not exist.
@@ -1771,6 +1779,7 @@ public void rootExplicit() {
}
@Test
+ @PlaybackOnly
public void rootExplicitInEndpoint() {
cc = primaryBlobServiceClient.getBlobContainerClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// create root container if not exist.
@@ -1788,6 +1797,7 @@ public void rootExplicitInEndpoint() {
}
@Test
+ @PlaybackOnly
public void blobClientBuilderRootImplicit() {
cc = primaryBlobServiceClient.getBlobContainerClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// createroot container if not exist.
@@ -1810,6 +1820,7 @@ public void blobClientBuilderRootImplicit() {
}
@Test
+ @PlaybackOnly
public void containerClientBuilderRootImplicit() {
cc = primaryBlobServiceClient.getBlobContainerClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// create root container if not exist.
@@ -1832,10 +1843,10 @@ public void containerClientBuilderRootImplicit() {
@Test
public void serviceClientImplicitRoot() {
- assertEquals(primaryBlobServiceClient.getBlobContainerClient(null).getBlobContainerName(),
- BlobContainerAsyncClient.ROOT_CONTAINER_NAME);
- assertEquals(primaryBlobServiceClient.getBlobContainerClient("").getBlobContainerName(),
- BlobContainerAsyncClient.ROOT_CONTAINER_NAME);
+ assertEquals(BlobContainerAsyncClient.ROOT_CONTAINER_NAME,
+ primaryBlobServiceClient.getBlobContainerClient(null).getBlobContainerName());
+ assertEquals(BlobContainerAsyncClient.ROOT_CONTAINER_NAME,
+ primaryBlobServiceClient.getBlobContainerClient("").getBlobContainerName());
}
@Test
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAsyncApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAsyncApiTests.java
index 3bb26f5c4741..fee4ef24df05 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAsyncApiTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAsyncApiTests.java
@@ -1122,38 +1122,46 @@ public void listBlobsFlatError() {
StepVerifier.create(ccAsync.listBlobs()).verifyError(BlobStorageException.class);
}
+ /*
+ * For listBlobsFlatWithTimeoutStillBackedByPagedFlux and listBlobsHierWithTimeoutStillBackedByPagedFlux:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
@Test
public void listBlobsFlatWithTimeoutStillBackedByPagedFlux() {
- int numBlobs = 5;
- int pageResults = 3;
-
- Mono> createBlob = Flux.range(0, numBlobs).flatMap(i -> {
- BlockBlobAsyncClient blob = ccAsync.getBlobAsyncClient(generateBlobName()).getBlockBlobAsyncClient();
- return blob.upload(DATA.getDefaultFlux(), DATA.getDefaultDataSize());
- }).collectList();
+ BlobContainerAsyncClient containerClient
+ = new BlobContainerClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .containerName("foo")
+ .httpClient(new ListBlobsWithTimeoutTestClient(true))
+ .buildAsyncClient();
- // when: "Consume results by page, then still have paging functionality"
StepVerifier
- .create(createBlob
- .thenMany(ccAsync.listBlobs(new ListBlobsOptions().setMaxResultsPerPage(pageResults)).byPage()))
+ .create(
+ containerClient
+ .listBlobsFlatWithOptionalTimeout(new ListBlobsOptions().setMaxResultsPerPage(3), null,
+ Duration.ofSeconds(6))
+ .byPage())
.expectNextCount(2)
.verifyComplete();
}
@Test
public void listBlobsHierWithTimeoutStillBackedByPagedFlux() {
- int numBlobs = 5;
- int pageResults = 3;
-
- Mono> createBlob = Flux.range(0, numBlobs).flatMap(i -> {
- BlockBlobAsyncClient blob = ccAsync.getBlobAsyncClient(generateBlobName()).getBlockBlobAsyncClient();
- return blob.upload(DATA.getDefaultFlux(), DATA.getDefaultDataSize());
- }).collectList();
+ BlobContainerAsyncClient containerClient
+ = new BlobContainerClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .containerName("foo")
+ .httpClient(new ListBlobsWithTimeoutTestClient(true))
+ .buildAsyncClient();
- // when: "Consume results by page, then still have paging functionality"
StepVerifier
- .create(createBlob.thenMany(
- ccAsync.listBlobsByHierarchy("/", new ListBlobsOptions().setMaxResultsPerPage(pageResults)).byPage()))
+ .create(containerClient
+ .listBlobsHierarchyWithOptionalTimeout("/", new ListBlobsOptions().setMaxResultsPerPage(3),
+ Duration.ofSeconds(6))
+ .byPage())
.expectNextCount(2)
.verifyComplete();
}
@@ -1776,33 +1784,27 @@ public void findBlobsError() {
StepVerifier.create(ccAsync.findBlobsByTags("garbageTag").byPage()).verifyError(BlobStorageException.class);
}
- @SuppressWarnings("deprecation")
+ /*
+ * For findBlobsWithTimeoutStillBackedByPagedFlux:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2021-04-10")
@Test
public void findBlobsWithTimeoutStillBackedByPagedFlux() {
- int numBlobs = 5;
- int pageResults = 3;
- Map tags = Collections.singletonMap(tagKey, tagValue);
-
- Mono>> uploadBlob = Flux.range(0, numBlobs)
- .flatMap(i -> ccAsync.getBlobAsyncClient(generateBlobName())
- .uploadWithResponse(
- new BlobParallelUploadOptions(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())
- .setTags(tags)))
- .collectList();
+ BlobContainerAsyncClient containerClient
+ = new BlobContainerClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .containerName("foo")
+ .httpClient(new FindBlobsWithTimeoutClient(true))
+ .buildAsyncClient();
- // when: "Consume results by page, still have paging functionality"
- StepVerifier
- .create(
- uploadBlob
- .thenMany(
- ccAsync
- .findBlobsByTags(new FindBlobsOptions(String.format("\"%s\"='%s'", tagKey, tagValue))
- .setMaxResultsPerPage(pageResults), Duration.ofSeconds(10), Context.NONE)
- .byPage()
- .count()))
- .expectNextCount(1)
- .verifyComplete();
+ StepVerifier.create(containerClient.findBlobsByTags(
+ new FindBlobsOptions(String.format("\"%s\"='%s'", "dummyKey", "dummyValue")).setMaxResultsPerPage(3),
+ Duration.ofSeconds(6), Context.NONE).byPage()).expectNextCount(2).verifyComplete();
}
@ParameterizedTest
@@ -1859,6 +1861,7 @@ public void createURLSpecialCharsEncoded(String name) {
}
@Test
+ @PlaybackOnly
public void rootExplicit() {
ccAsync = primaryBlobServiceAsyncClient.getBlobContainerAsyncClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// create root container if not exist.
@@ -1874,6 +1877,7 @@ public void rootExplicit() {
}
@Test
+ @PlaybackOnly
public void rootExplicitInEndpoint() {
ccAsync = primaryBlobServiceAsyncClient.getBlobContainerAsyncClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// create root container if not exist.
@@ -1893,6 +1897,7 @@ public void rootExplicitInEndpoint() {
}
@Test
+ @PlaybackOnly
public void blobClientBuilderRootImplicit() {
ccAsync = primaryBlobServiceAsyncClient.getBlobContainerAsyncClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// createroot container if not exist.
@@ -1917,6 +1922,7 @@ public void blobClientBuilderRootImplicit() {
}
@Test
+ @PlaybackOnly
public void containerClientBuilderRootImplicit() {
ccAsync = primaryBlobServiceAsyncClient.getBlobContainerAsyncClient(BlobContainerClient.ROOT_CONTAINER_NAME);
// create root container if not exist.
@@ -1945,10 +1951,10 @@ public void containerClientBuilderRootImplicit() {
@Test
public void serviceClientImplicitRoot() {
- assertEquals(primaryBlobServiceAsyncClient.getBlobContainerAsyncClient(null).getBlobContainerName(),
- BlobContainerAsyncClient.ROOT_CONTAINER_NAME);
- assertEquals(primaryBlobServiceAsyncClient.getBlobContainerAsyncClient("").getBlobContainerName(),
- BlobContainerAsyncClient.ROOT_CONTAINER_NAME);
+ assertEquals(BlobContainerAsyncClient.ROOT_CONTAINER_NAME,
+ primaryBlobServiceAsyncClient.getBlobContainerAsyncClient(null).getBlobContainerName());
+ assertEquals(BlobContainerAsyncClient.ROOT_CONTAINER_NAME,
+ primaryBlobServiceAsyncClient.getBlobContainerAsyncClient("").getBlobContainerName());
}
@Test
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceApiTests.java
index bec72862df0c..8fda9fd9cbd0 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceApiTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceApiTests.java
@@ -9,6 +9,7 @@
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.Response;
import com.azure.core.test.http.NoOpHttpClient;
+import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.util.Context;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.storage.blob.models.BlobAnalyticsLogging;
@@ -289,28 +290,28 @@ public void listContainersAnonymous() {
assertThrows(IllegalStateException.class, () -> anonymousClient.listBlobContainers().iterator());
}
+ /*
+ * For listContainersWithTimeoutStillBackedByPagedStream:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@Test
public void listContainersWithTimeoutStillBackedByPagedStream() {
- int numContainers = 5;
- int pageResults = 3;
-
- List containers = new ArrayList<>();
- for (int i = 0; i < numContainers; i++) {
- containers.add(primaryBlobServiceClient.createBlobContainer(generateContainerName()));
- }
+ BlobServiceClient serviceClient
+ = new BlobServiceClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .httpClient(new ListContainersWithTimeoutTestClient(false))
+ .buildClient();
- // when: "Consume results by page, then should still have paging functionality""
- assertDoesNotThrow(
- () -> primaryBlobServiceClient
- .listBlobContainers(new ListBlobContainersOptions().setMaxResultsPerPage(pageResults),
- Duration.ofSeconds(10))
+ assertEquals(2,
+ serviceClient
+ .listBlobContainers(new ListBlobContainersOptions().setMaxResultsPerPage(3), Duration.ofSeconds(14))
.streamByPage()
.count());
- // cleanup:
- for (BlobContainerClient container : containers) {
- container.delete();
- }
}
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-10-02")
@@ -525,30 +526,27 @@ public void findBlobsAnonymous() {
}
- @SuppressWarnings("deprecation")
+ /*
+ * For findBlobsWithTimeoutStillBackedByPagedStream:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2019-12-12")
@Test
public void findBlobsWithTimeoutStillBackedByPagedStream() {
- int numBlobs = 5;
- int pageResults = 3;
- BlobContainerClient cc = primaryBlobServiceClient.createBlobContainer(generateContainerName());
- Map tags = Collections.singletonMap(tagKey, tagValue);
-
- for (int i = 0; i < numBlobs; i++) {
- cc.getBlobClient(generateBlobName())
- .uploadWithResponse(
- new BlobParallelUploadOptions(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())
- .setTags(tags),
- null, null);
- }
-
- // when: "Consume results by page, then still have paging functionality"
- assertDoesNotThrow(() -> primaryBlobServiceClient.findBlobsByTags(
- new FindBlobsOptions(String.format("\"%s\"='%s'", tagKey, tagValue)).setMaxResultsPerPage(pageResults),
- Duration.ofSeconds(10), Context.NONE).streamByPage().count());
+ BlobServiceClient serviceClient
+ = new BlobServiceClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .httpClient(new FindBlobsWithTimeoutClient(false))
+ .buildClient();
- // cleanup:
- cc.delete();
+ assertEquals(2,
+ serviceClient.findBlobsByTags(
+ new FindBlobsOptions(String.format("\"%s\"='%s'", "dummyKey", "dummyValue")).setMaxResultsPerPage(3),
+ Duration.ofSeconds(14), Context.NONE).streamByPage().count());
}
private static void validatePropsSet(BlobServiceProperties sent, BlobServiceProperties received) {
@@ -1021,8 +1019,8 @@ public void restoreContainerWithResponse() {
sleepIfRunningAgainstService(30000);
Response response = primaryBlobServiceClient.undeleteBlobContainerWithResponse(
- new UndeleteBlobContainerOptions(blobContainerItem.getName(), blobContainerItem.getVersion()),
- Duration.ofMinutes(1), Context.NONE);
+ new UndeleteBlobContainerOptions(blobContainerItem.getName(), blobContainerItem.getVersion()), null,
+ Context.NONE);
BlobContainerClient restoredContainerClient = response.getValue();
assertNotNull(response);
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceAsyncApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceAsyncApiTests.java
index 55d8bd119202..8c679a5d2753 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceAsyncApiTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ServiceAsyncApiTests.java
@@ -8,6 +8,7 @@
import com.azure.core.http.rest.Response;
import com.azure.core.test.TestMode;
import com.azure.core.test.http.NoOpHttpClient;
+import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.util.Context;
import com.azure.core.util.paging.ContinuablePage;
import com.azure.identity.DefaultAzureCredentialBuilder;
@@ -285,20 +286,29 @@ public void listContainersAnonymous() {
StepVerifier.create(anonymousClient.listBlobContainers()).verifyError(IllegalStateException.class);
}
+ /*
+ * For listContainersWithTimeoutStillBackedByPagedFlux:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@Test
public void listContainersWithTimeoutStillBackedByPagedFlux() {
- int numContainers = 5;
- int pageResults = 3;
-
- Mono> containersMono = Flux.range(0, numContainers)
- .flatMap(i -> primaryBlobServiceAsyncClient.createBlobContainer(generateContainerName()))
- .collectList();
+ BlobServiceAsyncClient serviceClient
+ = new BlobServiceClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .httpClient(new ListContainersWithTimeoutTestClient(true))
+ .buildAsyncClient();
- StepVerifier.create(containersMono.flatMapMany(containers -> primaryBlobServiceAsyncClient
- .listBlobContainersWithOptionalTimeout(new ListBlobContainersOptions().setMaxResultsPerPage(pageResults),
- Duration.ofSeconds(10))
- .byPage()
- .count())).expectNextCount(1).verifyComplete();
+ StepVerifier
+ .create(serviceClient
+ .listBlobContainersWithOptionalTimeout(new ListBlobContainersOptions().setMaxResultsPerPage(3),
+ Duration.ofSeconds(6))
+ .byPage())
+ .expectNextCount(2)
+ .verifyComplete();
}
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-10-02")
@@ -500,28 +510,26 @@ public void findBlobsAnonymous() {
StepVerifier.create(anonymousClient.findBlobsByTags("foo=bar")).verifyError(IllegalStateException.class);
}
- @SuppressWarnings("deprecation")
+ /*
+ * For findBlobsWithTimeoutStillBackedByPagedFlux:
+ * The custom http client returns a generic xml list of 5 blobs total.
+ * The api call should return 2 pages, one page of 3 blobs and one page of 2 blobs.
+ * Although each page is set to take 4 seconds to return, the timeout being set to 6 seconds should not cause the test to fail,
+ * as the timeout is only on the page request and not the entire stream of pages.
+ */
+
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2019-12-12")
@Test
public void findBlobsWithTimeoutStillBackedByPagedFlux() {
- int numBlobs = 5;
- int pageResults = 3;
- Map tags = Collections.singletonMap(tagKey, tagValue);
-
- Mono response = primaryBlobServiceAsyncClient.createBlobContainer(generateContainerName()).flatMap(cc -> {
- Flux> upload = Flux.range(0, numBlobs)
- .flatMap(i -> cc.getBlobAsyncClient(generateBlobName())
- .uploadWithResponse(
- new BlobParallelUploadOptions(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())
- .setTags(tags)));
- // when: "Consume results by page, then still have paging functionality"
- return upload.then(primaryBlobServiceAsyncClient.findBlobsByTags(
- new FindBlobsOptions(String.format("\"%s\"='%s'", tagKey, tagValue)).setMaxResultsPerPage(pageResults))
- .byPage()
- .count());
- });
+ BlobServiceAsyncClient serviceClient
+ = new BlobServiceClientBuilder().endpoint("https://account.blob.core.windows.net/")
+ .credential(new MockTokenCredential())
+ .httpClient(new FindBlobsWithTimeoutClient(true))
+ .buildAsyncClient();
- StepVerifier.create(response).expectNextCount(1).verifyComplete();
+ StepVerifier.create(serviceClient.findBlobsByTags(
+ new FindBlobsOptions(String.format("\"%s\"='%s'", "dummyKey", "dummyValue")).setMaxResultsPerPage(3),
+ Duration.ofSeconds(6), Context.NONE).byPage()).expectNextCount(2).verifyComplete();
}
private static void validatePropsSet(BlobServiceProperties sent, BlobServiceProperties received) {
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobApiTests.java
index 7a00b9697dbc..7a4d162c7d85 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobApiTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobApiTests.java
@@ -1306,42 +1306,6 @@ private static Stream bufferedUploadSyncHandlePathingWithTransientFai
return Stream.of(Arguments.of(11110, 0), Arguments.of(2 * Constants.MB + 11, 2));
}
- /*
- def "Upload NRF progress"() {
- setup:
- def data = getRandomData(BlockBlobURL.MAX_UPLOAD_BLOB_BYTES + 1)
- def numBlocks = data.remaining() / BlockBlobURL.MAX_STAGE_BLOCK_BYTES
- long prevCount = 0
- def mockReceiver = Mock(IProgressReceiver)
-
-
- when:
- TransferManager.uploadFromNonReplayableFlowable(Flowable.just(data), bu, BlockBlobURL.MAX_STAGE_BLOCK_BYTES, 10,
- new TransferManagerUploadToBlockBlobOptions(mockReceiver, null, null, null, 20)).blockingGet()
- data.position(0)
-
- then:
- // We should receive exactly one notification of the completed progress.
- 1 * mockReceiver.reportProgress(data.remaining()) */
-
- /*
- We should receive at least one notification reporting an intermediary value per block, but possibly more
- notifications will be received depending on the implementation. We specify numBlocks - 1 because the last block
- will be the total size as above. Finally, we assert that the number reported monotonically increases.
- */
- /*(numBlocks - 1.._) * mockReceiver.reportProgress(!data.remaining()) >> { long bytesTransferred ->
- if (!(bytesTransferred > prevCount)) {
- throw new IllegalArgumentException("Reported progress should monotonically increase")
- } else {
- prevCount = bytesTransferred
- }
- }
-
- // We should receive no notifications that report more progress than the size of the file.
- 0 * mockReceiver.reportProgress({ it > data.remaining() })
- notThrown(IllegalArgumentException)
- }*/
-
@LiveOnly
@Test
public void bufferedUploadOverwrite() throws IOException {
@@ -1581,7 +1545,7 @@ public void uploadFromUrlSourceRequestConditions(BlobRequestConditions requestCo
private static Stream uploadFromUrlSourceRequestConditionsSupplier() {
return Stream.of(
Arguments.of(new BlobRequestConditions().setIfMatch("dummy"), BlobErrorCode.SOURCE_CONDITION_NOT_MET),
- Arguments.of(new BlobRequestConditions().setIfModifiedSince(OffsetDateTime.now().plusSeconds(20)),
+ Arguments.of(new BlobRequestConditions().setIfModifiedSince(OffsetDateTime.now().plusDays(10)),
BlobErrorCode.CANNOT_VERIFY_COPY_SOURCE),
Arguments.of(new BlobRequestConditions().setIfUnmodifiedSince(OffsetDateTime.now().minusDays(1)),
BlobErrorCode.CANNOT_VERIFY_COPY_SOURCE));
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAsyncApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAsyncApiTests.java
index d35e0afad279..eeec87686794 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAsyncApiTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/BlockBlobAsyncApiTests.java
@@ -2531,10 +2531,12 @@ public void uploadFromUrlSourceRequestConditions(BlobRequestConditions requestCo
Mono> response = sourceBlob.upload(DATA.getDefaultFlux(), null).flatMap(r -> {
String sas = sourceBlob.generateSas(new BlobServiceSasSignatureValues(testResourceNamer.now().plusDays(1),
new BlobContainerSasPermission().setReadPermission(true)));
- BlobUploadFromUrlOptions options = new BlobUploadFromUrlOptions(sourceBlob.getBlobUrl() + "?" + sas)
- .setSourceRequestConditions(requestConditions);
- return blockBlobAsyncClient.upload(Flux.just(ByteBuffer.wrap(new byte[0])), 0, true)
- .then(blockBlobAsyncClient.uploadFromUrlWithResponse(options));
+
+ return blockBlobAsyncClient.upload(Flux.just(ByteBuffer.wrap(new byte[0])), 0, true).flatMap(r2 -> {
+ BlobUploadFromUrlOptions options = new BlobUploadFromUrlOptions(sourceBlob.getBlobUrl() + "?" + sas)
+ .setSourceRequestConditions(requestConditions);
+ return blockBlobAsyncClient.uploadFromUrlWithResponse(options);
+ });
});
StepVerifier.create(response).verifyErrorSatisfies(r -> {
@@ -2546,7 +2548,7 @@ public void uploadFromUrlSourceRequestConditions(BlobRequestConditions requestCo
private static Stream uploadFromUrlSourceRequestConditionsSupplier() {
return Stream.of(
Arguments.of(new BlobRequestConditions().setIfMatch("dummy"), BlobErrorCode.SOURCE_CONDITION_NOT_MET),
- Arguments.of(new BlobRequestConditions().setIfModifiedSince(OffsetDateTime.now().plusSeconds(10)),
+ Arguments.of(new BlobRequestConditions().setIfModifiedSince(OffsetDateTime.now().plusDays(10)),
BlobErrorCode.CANNOT_VERIFY_COPY_SOURCE),
Arguments.of(new BlobRequestConditions().setIfUnmodifiedSince(OffsetDateTime.now().minusDays(1)),
BlobErrorCode.CANNOT_VERIFY_COPY_SOURCE));
diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HttpFaultInjectingTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HttpFaultInjectingTests.java
index 565a9b7e44e2..11c9afd38598 100644
--- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HttpFaultInjectingTests.java
+++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/specialized/HttpFaultInjectingTests.java
@@ -6,8 +6,6 @@
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpClientProvider;
import com.azure.core.http.HttpHeaderName;
-import com.azure.core.http.HttpRequest;
-import com.azure.core.http.HttpResponse;
import com.azure.core.http.netty.NettyAsyncHttpClientProvider;
import com.azure.core.http.okhttp.OkHttpAsyncClientProvider;
import com.azure.core.test.TestMode;
@@ -17,7 +15,6 @@
import com.azure.core.util.CoreUtils;
import com.azure.core.util.HttpClientOptions;
import com.azure.core.util.SharedExecutorService;
-import com.azure.core.util.UrlBuilder;
import com.azure.core.util.logging.ClientLogger;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobClientBuilder;
@@ -33,12 +30,9 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
-import reactor.core.publisher.Mono;
import java.io.File;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
@@ -56,6 +50,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
+import static com.azure.core.test.utils.TestUtils.getFaultInjectingHttpClient;
import static com.azure.storage.blob.BlobTestBase.ENVIRONMENT;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -112,7 +107,7 @@ public void downloadToFileWithFaultInjection() throws IOException, InterruptedEx
.containerName(containerClient.getBlobContainerName())
.blobName(containerClient.getBlobContainerName())
.credential(ENVIRONMENT.getPrimaryAccount().getCredential())
- .httpClient(new HttpFaultInjectingHttpClient(getFaultInjectingWrappedHttpClient()))
+ .httpClient(getFaultInjectingHttpClient(getFaultInjectingWrappedHttpClient(), false))
.retryOptions(new RequestRetryOptions(RetryPolicyType.FIXED, 4, null, 10L, 10L, null))
.buildClient();
@@ -155,7 +150,8 @@ public void downloadToFileWithFaultInjection() throws IOException, InterruptedEx
countDownLatch.await(10, TimeUnit.MINUTES);
- assertTrue(successCount.get() >= 450);
+ assertTrue(successCount.get() >= 450,
+ () -> "Expected over 450 successes, actual success count was: " + successCount.get());
// cleanup
files.forEach(it -> {
try {
@@ -170,8 +166,8 @@ public void downloadToFileWithFaultInjection() throws IOException, InterruptedEx
private HttpClient getFaultInjectingWrappedHttpClient() {
switch (ENVIRONMENT.getHttpClientType()) {
case NETTY:
- return HttpClient.createDefault(new HttpClientOptions().readTimeout(Duration.ofSeconds(2))
- .responseTimeout(Duration.ofSeconds(2))
+ return HttpClient.createDefault(new HttpClientOptions().readTimeout(Duration.ofSeconds(5))
+ .responseTimeout(Duration.ofSeconds(5))
.setHttpClientProvider(NettyAsyncHttpClientProvider.class));
case OK_HTTP:
@@ -216,95 +212,6 @@ private static Class extends HttpClientProvider> getVertxClientProviderReflect
return (Class extends HttpClientProvider>) clazz;
}
- // For now a local implementation is here in azure-storage-blob until this is released in azure-core-test.
- // Since this is a local definition with a clear set of configurations everything is simplified.
- private static final class HttpFaultInjectingHttpClient implements HttpClient {
- private final HttpClient wrappedHttpClient;
-
- HttpFaultInjectingHttpClient(HttpClient wrappedHttpClient) {
- this.wrappedHttpClient = wrappedHttpClient;
- }
-
- @Override
- public Mono send(HttpRequest request) {
- return send(request, Context.NONE);
- }
-
- @Override
- public Mono send(HttpRequest request, Context context) {
- URL originalUrl = request.getUrl();
- request.setHeader(UPSTREAM_URI_HEADER, originalUrl.toString()).setUrl(rewriteUrl(originalUrl));
- String faultType = faultInjectorHandling();
- request.setHeader(HTTP_FAULT_INJECTOR_RESPONSE_HEADER, faultType);
-
- return wrappedHttpClient.send(request, context).map(response -> {
- HttpRequest request1 = response.getRequest();
- request1.getHeaders().remove(UPSTREAM_URI_HEADER);
- request1.setUrl(originalUrl);
-
- return response;
- });
- }
-
- @Override
- public HttpResponse sendSync(HttpRequest request, Context context) {
- URL originalUrl = request.getUrl();
- request.setHeader(UPSTREAM_URI_HEADER, originalUrl.toString()).setUrl(rewriteUrl(originalUrl));
- String faultType = faultInjectorHandling();
- request.setHeader(HTTP_FAULT_INJECTOR_RESPONSE_HEADER, faultType);
-
- HttpResponse response = wrappedHttpClient.sendSync(request, context);
- response.getRequest().setUrl(originalUrl);
- response.getRequest().getHeaders().remove(UPSTREAM_URI_HEADER);
-
- return response;
- }
-
- private static URL rewriteUrl(URL originalUrl) {
- try {
- return UrlBuilder.parse(originalUrl).setScheme("http").setHost("localhost").setPort(7777).toUrl();
- } catch (MalformedURLException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static String faultInjectorHandling() {
- // f: Full response
- // p: Partial Response (full headers, 50% of body), then wait indefinitely
- // pc: Partial Response (full headers, 50% of body), then close (TCP FIN)
- // pa: Partial Response (full headers, 50% of body), then abort (TCP RST)
- // pn: Partial Response (full headers, 50% of body), then finish normally
- // n: No response, then wait indefinitely
- // nc: No response, then close (TCP FIN)
- // na: No response, then abort (TCP RST)
- double random = ThreadLocalRandom.current().nextDouble();
- int choice = (int) (random * 100);
-
- if (choice >= 25) {
- // 75% of requests complete without error.
- return "f";
- } else if (choice >= 1) {
- if (random <= 0.34D) {
- return "n";
- } else if (random <= 0.67D) {
- return "nc";
- } else {
- return "na";
- }
- } else {
- if (random <= 0.25D) {
- return "p";
- } else if (random <= 0.50D) {
- return "pc";
- } else if (random <= 0.75D) {
- return "pa";
- } else {
- return "pn";
- }
- }
- }
- }
-
private static boolean shouldRun() {
String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT);