Skip to content

Commit 3c52dde

Browse files
authored
Adding New Isolated Timeout Test Class (Azure#45202)
* potential fault injection fix * removing redundant class * removing timeout from args to align with other tests that use this api * making supplier match sync test, which does not have flakiness problems * increasing response and read timeout again * wip * removing management plane interaction and replacing with data plane interaction so it doesnt explode with 429s * changing seconds to days to match uploadFromUrlDestinationRequestConditionsSupplier * making root tests playback only to resolve race conditions due to parallelism * removing a test that was literally never used * adding mocking to list resource tests * adding recordings * increasing timeouts for sync tests * fixing timeout mistake in ternary operator * moving timeout tests to an isolated test file * removing timeout difference between sync and async * removing unused method and moving variables * removing another unused method, changing util method names, and reducing redundancy * removing everything besides timeout test changes to put into another PR * format fix * spotless * changing assets tag back to what it was before * fixing sync timeout * refactoring timeout test class helper method * style * style * refactoring timeout test class helper method (x2) * generalizing xml building methods * removing instance property counters * adding todo comment
1 parent 75116b2 commit 3c52dde

File tree

7 files changed

+387
-212
lines changed

7 files changed

+387
-212
lines changed

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

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.azure.core.http.rest.Response;
2323
import com.azure.core.test.TestMode;
2424
import com.azure.core.test.TestProxyTestBase;
25+
import com.azure.core.test.http.MockHttpResponse;
2526
import com.azure.core.test.models.CustomMatcher;
2627
import com.azure.core.test.models.TestProxySanitizer;
2728
import com.azure.core.test.models.TestProxySanitizerType;
@@ -62,11 +63,14 @@
6263
import com.azure.storage.common.test.shared.TestDataFactory;
6364
import com.azure.storage.common.test.shared.TestEnvironment;
6465
import com.azure.storage.common.test.shared.policy.PerCallVersionPolicy;
66+
import com.azure.xml.XmlWriter;
6567
import org.junit.jupiter.params.provider.Arguments;
6668
import reactor.core.publisher.Flux;
6769
import reactor.core.publisher.Mono;
6870
import reactor.test.StepVerifier;
6971

72+
import javax.xml.stream.XMLStreamException;
73+
import java.io.ByteArrayOutputStream;
7074
import java.io.File;
7175
import java.io.IOException;
7276
import java.io.InputStream;
@@ -82,6 +86,8 @@
8286
import java.util.Collections;
8387
import java.util.List;
8488
import java.util.Objects;
89+
import java.util.Queue;
90+
import java.util.concurrent.Callable;
8591
import java.util.function.Supplier;
8692
import java.util.stream.Collectors;
8793
import java.util.stream.Stream;
@@ -1073,4 +1079,162 @@ protected static TokenCredential getTokenCredential(TestMode testMode) {
10731079
return new MockTokenCredential();
10741080
}
10751081
}
1082+
1083+
// todo (isbr): https://github.com/Azure/azure-sdk-for-java/pull/45202#pullrequestreview-2915149773
1084+
protected static final class PagingTimeoutTestClient implements HttpClient {
1085+
private final Queue<String> responses = new java.util.LinkedList<>();
1086+
1087+
private enum PageType {
1088+
LIST_BLOBS, FIND_BLOBS, LIST_CONTAINERS
1089+
}
1090+
1091+
public PagingTimeoutTestClient() {
1092+
}
1093+
1094+
public PagingTimeoutTestClient addListBlobsResponses(int totalResourcesExpected, int maxResourcesPerPage,
1095+
boolean isHierarchical) {
1096+
return addPagedResponses(totalResourcesExpected, maxResourcesPerPage, PageType.LIST_BLOBS, isHierarchical);
1097+
}
1098+
1099+
public PagingTimeoutTestClient addFindBlobsResponses(int totalResourcesExpected, int maxResourcesPerPage) {
1100+
return addPagedResponses(totalResourcesExpected, maxResourcesPerPage, PageType.FIND_BLOBS, false);
1101+
}
1102+
1103+
public PagingTimeoutTestClient addListContainersResponses(int totalResourcesExpected, int maxResourcesPerPage) {
1104+
return addPagedResponses(totalResourcesExpected, maxResourcesPerPage, PageType.LIST_CONTAINERS, false);
1105+
}
1106+
1107+
private PagingTimeoutTestClient addPagedResponses(int totalResourcesExpected, int maxResourcesPerPage,
1108+
PageType pageType, boolean isHierarchical) {
1109+
int totalPagesExpected = (int) Math.ceil((double) totalResourcesExpected / maxResourcesPerPage);
1110+
int resourcesAdded = 0;
1111+
for (int pageNum = 0; pageNum < totalPagesExpected; pageNum++) {
1112+
int numberOfElementsOnThisPage = Math.min(maxResourcesPerPage, totalResourcesExpected - resourcesAdded);
1113+
resourcesAdded += numberOfElementsOnThisPage;
1114+
1115+
try {
1116+
responses.add(buildXmlPage(pageNum, maxResourcesPerPage, totalPagesExpected,
1117+
numberOfElementsOnThisPage, pageType, isHierarchical));
1118+
} catch (Exception e) {
1119+
throw new RuntimeException("Failed to generate XML for paged response", e);
1120+
}
1121+
}
1122+
return this;
1123+
}
1124+
1125+
private String buildXmlPage(int pageNum, int maxResourcesPerPage, int totalPagesExpected,
1126+
int numberOfElementsOnThisPage, PageType pageType, boolean isHierarchicalForBlobs) throws Exception {
1127+
ByteArrayOutputStream output = new ByteArrayOutputStream();
1128+
XmlWriter xmlWriter = XmlWriter.toStream(output);
1129+
1130+
String elementType;
1131+
Callable<Void> additionalElements = null;
1132+
1133+
switch (pageType) {
1134+
case LIST_BLOBS:
1135+
elementType = "Blob";
1136+
startXml(pageNum, xmlWriter, () -> {
1137+
xmlWriter.writeStringAttribute("ContainerName", "foo");
1138+
return null;
1139+
});
1140+
xmlWriter.writeStringElement("MaxResults", String.valueOf(maxResourcesPerPage));
1141+
if (isHierarchicalForBlobs) {
1142+
xmlWriter.writeStringElement("Delimiter", "/");
1143+
}
1144+
break;
1145+
1146+
case FIND_BLOBS:
1147+
elementType = "Blob";
1148+
additionalElements = () -> {
1149+
xmlWriter.writeStringElement("ContainerName", "foo");
1150+
1151+
// Write Tags
1152+
xmlWriter.writeStartElement("Tags");
1153+
xmlWriter.writeStartElement("TagSet");
1154+
xmlWriter.writeStartElement("Tag");
1155+
xmlWriter.writeStringElement("Key", "dummyKey");
1156+
xmlWriter.writeStringElement("Value", "dummyValue");
1157+
xmlWriter.writeEndElement(); // End Tag
1158+
xmlWriter.writeEndElement(); // End TagSet
1159+
xmlWriter.writeEndElement(); // End Tags
1160+
return null;
1161+
};
1162+
startXml(pageNum, xmlWriter, null);
1163+
xmlWriter.writeStringElement("Where", "\"dummyKey\"='dummyValue'");
1164+
xmlWriter.writeStringElement("MaxResults", String.valueOf(maxResourcesPerPage));
1165+
break;
1166+
1167+
case LIST_CONTAINERS:
1168+
elementType = "Container";
1169+
startXml(pageNum, xmlWriter, null);
1170+
xmlWriter.writeStringElement("MaxResults", String.valueOf(maxResourcesPerPage));
1171+
break;
1172+
1173+
default:
1174+
throw new IllegalArgumentException("Unknown PageType: " + pageType);
1175+
}
1176+
1177+
writeGenericListElement(xmlWriter, elementType, numberOfElementsOnThisPage, additionalElements);
1178+
endXml(pageNum, xmlWriter, totalPagesExpected); // This calls flush
1179+
1180+
return output.toString();
1181+
}
1182+
1183+
private void startXml(int pageNum, XmlWriter xmlWriter, Callable<Void> additionalAttributes) throws Exception {
1184+
xmlWriter.writeStartDocument();
1185+
xmlWriter.writeStartElement("EnumerationResults");
1186+
xmlWriter.writeStringAttribute("ServiceEndpoint", "https://account.blob.core.windows.net/");
1187+
1188+
if (additionalAttributes != null) {
1189+
additionalAttributes.call();
1190+
}
1191+
1192+
// Write marker if not first page
1193+
if (pageNum != 0) {
1194+
xmlWriter.writeStringElement("Marker", "MARKER--");
1195+
}
1196+
}
1197+
1198+
private void endXml(int pageNum, XmlWriter xmlWriter, int totalPagesExpected) throws XMLStreamException {
1199+
// Write NextMarker
1200+
if (pageNum == totalPagesExpected - 1) {
1201+
xmlWriter.writeStringElement("NextMarker", null);
1202+
} else {
1203+
xmlWriter.writeStringElement("NextMarker", "MARKER--");
1204+
}
1205+
1206+
xmlWriter.writeEndElement(); // End EnumerationResults
1207+
xmlWriter.flush();
1208+
}
1209+
1210+
private void writeGenericListElement(XmlWriter xmlWriter, String elementType, int numberOfElementsOnThisPage,
1211+
Callable<Void> additionalElements) throws Exception {
1212+
// Start elementType + s
1213+
xmlWriter.writeStartElement(elementType + "s");
1214+
1215+
// Write entries
1216+
for (int i = 0; i < numberOfElementsOnThisPage; i++) {
1217+
xmlWriter.writeStartElement(elementType); // Start elementType
1218+
xmlWriter.writeStringElement("Name", elementType.toLowerCase());
1219+
1220+
if (additionalElements != null) {
1221+
additionalElements.call();
1222+
}
1223+
1224+
xmlWriter.writeEndElement(); // End elementType
1225+
}
1226+
1227+
xmlWriter.writeEndElement(); // End elementType + s
1228+
}
1229+
1230+
@Override
1231+
public Mono<HttpResponse> send(HttpRequest request) {
1232+
HttpHeaders headers = new HttpHeaders().set(HttpHeaderName.CONTENT_TYPE, "application/xml");
1233+
HttpResponse response
1234+
= new MockHttpResponse(request, 200, headers, responses.poll().getBytes(StandardCharsets.UTF_8));
1235+
1236+
int requestDelaySeconds = 4;
1237+
return Mono.delay(Duration.ofSeconds(requestDelaySeconds)).then(Mono.just(response));
1238+
}
1239+
}
10761240
}

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

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959

6060
import java.io.ByteArrayInputStream;
6161
import java.net.URL;
62-
import java.time.Duration;
6362
import java.time.OffsetDateTime;
6463
import java.util.Arrays;
6564
import java.util.Base64;
@@ -1070,40 +1069,6 @@ public void listBlobsFlatError() {
10701069
assertThrows(BlobStorageException.class, () -> cc.listBlobs().iterator().hasNext());
10711070
}
10721071

1073-
@Test
1074-
public void listBlobsFlatWithTimeoutStillBackedByPagedStream() {
1075-
int numBlobs = 5;
1076-
int pageResults = 3;
1077-
1078-
for (int i = 0; i < numBlobs; i++) {
1079-
BlockBlobClient blob = cc.getBlobClient(generateBlobName()).getBlockBlobClient();
1080-
blob.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize());
1081-
}
1082-
1083-
// when: "Consume results by page, then still have paging functionality"
1084-
assertDoesNotThrow(
1085-
() -> cc.listBlobs(new ListBlobsOptions().setMaxResultsPerPage(pageResults), Duration.ofSeconds(10))
1086-
.streamByPage()
1087-
.count());
1088-
}
1089-
1090-
@Test
1091-
public void listBlobsHierWithTimeoutStillBackedByPagedStream() {
1092-
int numBlobs = 5;
1093-
int pageResults = 3;
1094-
1095-
for (int i = 0; i < numBlobs; i++) {
1096-
BlockBlobClient blob = cc.getBlobClient(generateBlobName()).getBlockBlobClient();
1097-
blob.upload(DATA.getDefaultInputStream(), DATA.getDefaultDataSize());
1098-
}
1099-
1100-
// when: "Consume results by page, then still have paging functionality"
1101-
assertDoesNotThrow(() -> cc
1102-
.listBlobsByHierarchy("/", new ListBlobsOptions().setMaxResultsPerPage(pageResults), Duration.ofSeconds(10))
1103-
.streamByPage()
1104-
.count());
1105-
}
1106-
11071072
/*
11081073
This test requires two accounts that are configured in a very specific way. It is not feasible to setup that
11091074
relationship programmatically, so we have recorded a successful interaction and only test recordings.
@@ -1656,28 +1621,6 @@ public void findBlobsError() {
16561621
assertThrows(BlobStorageException.class, () -> cc.findBlobsByTags("garbageTag").streamByPage().count());
16571622
}
16581623

1659-
@SuppressWarnings("deprecation")
1660-
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2021-04-10")
1661-
@Test
1662-
public void findBlobsWithTimeoutStillBackedByPagedStream() {
1663-
int numBlobs = 5;
1664-
int pageResults = 3;
1665-
Map<String, String> tags = Collections.singletonMap(tagKey, tagValue);
1666-
1667-
for (int i = 0; i < numBlobs; i++) {
1668-
cc.getBlobClient(generateBlobName())
1669-
.uploadWithResponse(
1670-
new BlobParallelUploadOptions(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())
1671-
.setTags(tags),
1672-
null, null);
1673-
}
1674-
1675-
// when: "Consume results by page, still have paging functionality"
1676-
assertDoesNotThrow(() -> cc.findBlobsByTags(
1677-
new FindBlobsOptions(String.format("\"%s\"='%s'", tagKey, tagValue)).setMaxResultsPerPage(pageResults),
1678-
Duration.ofSeconds(10), Context.NONE).streamByPage().count());
1679-
}
1680-
16811624
@ParameterizedTest
16821625
@ValueSource(strings = { "中文", "az[]", "hello world", "hello/world", "hello&world", "!*'();:@&=+/$,/?#[]" })
16831626
public void createURLSpecialChars(String name) {

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

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,42 +1122,6 @@ public void listBlobsFlatError() {
11221122
StepVerifier.create(ccAsync.listBlobs()).verifyError(BlobStorageException.class);
11231123
}
11241124

1125-
@Test
1126-
public void listBlobsFlatWithTimeoutStillBackedByPagedFlux() {
1127-
int numBlobs = 5;
1128-
int pageResults = 3;
1129-
1130-
Mono<List<BlockBlobItem>> createBlob = Flux.range(0, numBlobs).flatMap(i -> {
1131-
BlockBlobAsyncClient blob = ccAsync.getBlobAsyncClient(generateBlobName()).getBlockBlobAsyncClient();
1132-
return blob.upload(DATA.getDefaultFlux(), DATA.getDefaultDataSize());
1133-
}).collectList();
1134-
1135-
// when: "Consume results by page, then still have paging functionality"
1136-
StepVerifier
1137-
.create(createBlob
1138-
.thenMany(ccAsync.listBlobs(new ListBlobsOptions().setMaxResultsPerPage(pageResults)).byPage()))
1139-
.expectNextCount(2)
1140-
.verifyComplete();
1141-
}
1142-
1143-
@Test
1144-
public void listBlobsHierWithTimeoutStillBackedByPagedFlux() {
1145-
int numBlobs = 5;
1146-
int pageResults = 3;
1147-
1148-
Mono<List<BlockBlobItem>> createBlob = Flux.range(0, numBlobs).flatMap(i -> {
1149-
BlockBlobAsyncClient blob = ccAsync.getBlobAsyncClient(generateBlobName()).getBlockBlobAsyncClient();
1150-
return blob.upload(DATA.getDefaultFlux(), DATA.getDefaultDataSize());
1151-
}).collectList();
1152-
1153-
// when: "Consume results by page, then still have paging functionality"
1154-
StepVerifier
1155-
.create(createBlob.thenMany(
1156-
ccAsync.listBlobsByHierarchy("/", new ListBlobsOptions().setMaxResultsPerPage(pageResults)).byPage()))
1157-
.expectNextCount(2)
1158-
.verifyComplete();
1159-
}
1160-
11611125
/*
11621126
This test requires two accounts that are configured in a very specific way. It is not feasible to setup that
11631127
relationship programmatically, so we have recorded a successful interaction and only test recordings.
@@ -1776,35 +1740,6 @@ public void findBlobsError() {
17761740
StepVerifier.create(ccAsync.findBlobsByTags("garbageTag").byPage()).verifyError(BlobStorageException.class);
17771741
}
17781742

1779-
@SuppressWarnings("deprecation")
1780-
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2021-04-10")
1781-
@Test
1782-
public void findBlobsWithTimeoutStillBackedByPagedFlux() {
1783-
int numBlobs = 5;
1784-
int pageResults = 3;
1785-
Map<String, String> tags = Collections.singletonMap(tagKey, tagValue);
1786-
1787-
Mono<List<Response<BlockBlobItem>>> uploadBlob = Flux.range(0, numBlobs)
1788-
.flatMap(i -> ccAsync.getBlobAsyncClient(generateBlobName())
1789-
.uploadWithResponse(
1790-
new BlobParallelUploadOptions(DATA.getDefaultInputStream(), DATA.getDefaultDataSize())
1791-
.setTags(tags)))
1792-
.collectList();
1793-
1794-
// when: "Consume results by page, still have paging functionality"
1795-
StepVerifier
1796-
.create(
1797-
uploadBlob
1798-
.thenMany(
1799-
ccAsync
1800-
.findBlobsByTags(new FindBlobsOptions(String.format("\"%s\"='%s'", tagKey, tagValue))
1801-
.setMaxResultsPerPage(pageResults), Duration.ofSeconds(10), Context.NONE)
1802-
.byPage()
1803-
.count()))
1804-
.expectNextCount(1)
1805-
.verifyComplete();
1806-
}
1807-
18081743
@ParameterizedTest
18091744
@ValueSource(strings = { "中文", "az[]", "hello world", "hello/world", "hello&world", "!*'();:@&=+/$,/?#[]" })
18101745
public void createURLSpecialChars(String name) {

0 commit comments

Comments
 (0)