Skip to content

Commit dc4ff8c

Browse files
authored
Fix missing flush in testReadBlobWithPrematureConnectionClose (#114094)
* Fix missing flush in `testReadBlobWithPrematureConnectionClose` It seems that JDK23 yields a different error message if the connection is closed before even sending headers. This commit relaxes the assertion to match, and also tightens it up to check that we report a premature end of the body if we _do_ send headers. Backport of #113609 to `7.x` Closes #114016 * Fix license header
1 parent e0d411f commit dc4ff8c

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

test/framework/src/main/java/org/elasticsearch/repositories/blobstore/AbstractBlobContainerRetriesTestCase.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import java.util.regex.Matcher;
4242
import java.util.regex.Pattern;
4343

44+
import static org.elasticsearch.test.NeverMatcher.never;
45+
import static org.hamcrest.Matchers.anyOf;
4446
import static org.hamcrest.Matchers.containsString;
4547
import static org.hamcrest.Matchers.either;
4648
import static org.hamcrest.Matchers.equalTo;
@@ -277,9 +279,12 @@ public void testReadBlobWithReadTimeouts() {
277279
assertThat(exception, readTimeoutExceptionMatcher());
278280
assertThat(
279281
exception.getMessage().toLowerCase(Locale.ROOT),
280-
either(containsString("read timed out")).or(containsString("premature end of chunk coded message body: closing chunk expected"))
281-
.or(containsString("Read timed out"))
282-
.or(containsString("unexpected end of file from server"))
282+
anyOf(
283+
containsString("read timed out"),
284+
containsString("premature end of chunk coded message body: closing chunk expected"),
285+
containsString("Read timed out"),
286+
containsString("unexpected end of file from server")
287+
)
283288
);
284289
assertThat(exception.getSuppressed().length, equalTo(maxRetries));
285290
}
@@ -308,10 +313,15 @@ public void testReadBlobWithPrematureConnectionClose() {
308313
final int maxRetries = randomInt(20);
309314
final BlobContainer blobContainer = createBlobContainer(maxRetries, null, null, null);
310315

316+
final boolean alwaysFlushBody = randomBoolean();
317+
311318
// HTTP server sends a partial response
312319
final byte[] bytes = randomBlobContent(1);
313320
httpServer.createContext(downloadStorageEndpoint(blobContainer, "read_blob_incomplete"), exchange -> {
314321
sendIncompleteContent(exchange, bytes);
322+
if (alwaysFlushBody) {
323+
exchange.getResponseBody().flush();
324+
}
315325
exchange.close();
316326
});
317327

@@ -326,9 +336,14 @@ public void testReadBlobWithPrematureConnectionClose() {
326336
});
327337
assertThat(
328338
exception.getMessage().toLowerCase(Locale.ROOT),
329-
either(containsString("premature end of chunk coded message body: closing chunk expected")).or(
330-
containsString("premature end of content-length delimited message body")
331-
).or(containsString("connection closed prematurely"))
339+
anyOf(
340+
// closing the connection after sending the headers and some incomplete body might yield one of these:
341+
containsString("premature end of chunk coded message body: closing chunk expected"),
342+
containsString("premature end of content-length delimited message body"),
343+
containsString("connection closed prematurely"),
344+
// if we didn't call exchange.getResponseBody().flush() then we might not even have sent the response headers:
345+
alwaysFlushBody ? never() : containsString("the target server failed to respond")
346+
)
332347
);
333348
assertThat(exception.getSuppressed().length, equalTo(Math.min(10, maxRetries)));
334349
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.test;
10+
11+
import org.hamcrest.BaseMatcher;
12+
import org.hamcrest.Description;
13+
import org.hamcrest.Matcher;
14+
15+
public class NeverMatcher<T> extends BaseMatcher<T> {
16+
@SuppressWarnings("unchecked")
17+
public static <T> Matcher<T> never() {
18+
return (Matcher<T>) INSTANCE;
19+
}
20+
21+
private static final Matcher<?> INSTANCE = new NeverMatcher<>();
22+
23+
private NeverMatcher() {/* singleton */}
24+
25+
@Override
26+
public boolean matches(Object actual) {
27+
return false;
28+
}
29+
30+
@Override
31+
public void describeTo(Description description) {
32+
description.appendText("never matches");
33+
}
34+
}

0 commit comments

Comments
 (0)