Skip to content

Commit 90b4006

Browse files
committed
8305847: Improve diagnosability and resilience of HttpClient::close tests
Reviewed-by: jpai, djelinski
1 parent d7dc474 commit 90b4006

File tree

4 files changed

+224
-110
lines changed

4 files changed

+224
-110
lines changed

test/jdk/java/net/httpclient/AsyncShutdownNow.java

+32-31
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
import java.io.InputStream;
4343
import java.io.OutputStream;
4444
import java.io.UncheckedIOException;
45-
import java.net.InetAddress;
46-
import java.net.InetSocketAddress;
4745
import java.net.URI;
4846
import java.net.http.HttpClient;
4947
import java.net.http.HttpClient.Redirect;
@@ -62,18 +60,11 @@
6260
import java.util.concurrent.ExecutionException;
6361
import java.util.concurrent.ExecutorService;
6462
import java.util.concurrent.Executors;
65-
import java.util.concurrent.RejectedExecutionException;
6663
import java.util.concurrent.TimeUnit;
6764
import java.util.concurrent.atomic.AtomicLong;
68-
import java.util.function.Function;
6965
import jdk.httpclient.test.lib.common.HttpServerAdapters;
70-
import jdk.httpclient.test.lib.http2.Http2TestServer;
7166
import javax.net.ssl.SSLContext;
72-
import javax.net.ssl.SSLHandshakeException;
7367

74-
import com.sun.net.httpserver.HttpServer;
75-
import com.sun.net.httpserver.HttpsConfigurator;
76-
import com.sun.net.httpserver.HttpsServer;
7768
import jdk.test.lib.RandomFactory;
7869
import jdk.test.lib.net.SimpleSSLContext;
7970
import org.testng.annotations.AfterTest;
@@ -99,6 +90,7 @@ public class AsyncShutdownNow implements HttpServerAdapters {
9990
}
10091
static final Random RANDOM = RandomFactory.getRandom();
10192

93+
ExecutorService readerService;
10294
SSLContext sslContext;
10395
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
10496
HttpTestServer httpsTestServer; // HTTPS/1.1
@@ -123,7 +115,7 @@ public Object[][] positive() {
123115
}
124116

125117
static final AtomicLong requestCounter = new AtomicLong();
126-
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
118+
static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
127119

128120
static Throwable getCause(Throwable t) {
129121
while (t instanceof CompletionException || t instanceof ExecutionException) {
@@ -175,8 +167,7 @@ static void checkCause(String what, Throwable cause) {
175167

176168
@Test(dataProvider = "positive")
177169
void testConcurrent(String uriString) throws Exception {
178-
out.printf("%n---- starting (%s) ----%n", uriString);
179-
ExecutorService readerService = Executors.newCachedThreadPool();
170+
out.printf("%n---- starting concurrent (%s) ----%n%n", uriString);
180171
HttpClient client = HttpClient.newBuilder()
181172
.proxy(NO_PROXY)
182173
.followRedirects(Redirect.ALWAYS)
@@ -186,8 +177,8 @@ void testConcurrent(String uriString) throws Exception {
186177

187178
int step = RANDOM.nextInt(ITERATIONS);
188179
Throwable failed = null;
180+
List<CompletableFuture<String>> bodies = new ArrayList<>();
189181
try {
190-
List<CompletableFuture<String>> bodies = new ArrayList<>();
191182
for (int i = 0; i < ITERATIONS; i++) {
192183
URI uri = URI.create(uriString + "/concurrent/iteration-" + i);
193184
HttpRequest request = HttpRequest.newBuilder(uri)
@@ -232,31 +223,31 @@ void testConcurrent(String uriString) throws Exception {
232223
});
233224
bodies.add(cf);
234225
}
235-
CompletableFuture.allOf(bodies.toArray(new CompletableFuture<?>[0])).get();
236226
} catch (Throwable throwable) {
237227
failed = throwable;
238228
} finally {
239-
failed = cleanup(client, readerService, failed);
229+
failed = cleanup(client, failed);
240230
}
241231
if (failed instanceof Exception ex) throw ex;
242232
if (failed instanceof Error e) throw e;
243233
assertTrue(client.isTerminated());
234+
// ensure that all operations are eventually terminated
235+
CompletableFuture.allOf(bodies.toArray(new CompletableFuture<?>[0])).get();
244236
}
245237

246-
static Throwable cleanup(HttpClient client, ExecutorService readerService, Throwable failed) {
238+
static Throwable cleanup(HttpClient client, Throwable failed) {
247239
try {
248-
try {
249-
if (client.awaitTermination(Duration.ofMillis(2000))) {
250-
out.println("Client terminated within expected delay");
251-
} else {
252-
AssertionError error = new AssertionError("client still running");
253-
if (failed != null) {
254-
failed.addSuppressed(error);
255-
} else failed = error;
256-
}
257-
} finally {
258-
readerService.shutdown();
259-
readerService.awaitTermination(2000, TimeUnit.MILLISECONDS);
240+
if (client.awaitTermination(Duration.ofMillis(2000))) {
241+
out.println("Client terminated within expected delay");
242+
} else {
243+
String msg = "Client %s still running: %s".formatted(
244+
client,
245+
TRACKER.diagnose(client));
246+
out.println(msg);
247+
AssertionError error = new AssertionError(msg);
248+
if (failed != null) {
249+
failed.addSuppressed(error);
250+
} else failed = error;
260251
}
261252
} catch (InterruptedException ie) {
262253
if (failed != null) {
@@ -268,8 +259,7 @@ static Throwable cleanup(HttpClient client, ExecutorService readerService, Throw
268259

269260
@Test(dataProvider = "positive")
270261
void testSequential(String uriString) throws Exception {
271-
out.printf("%n---- starting (%s) ----%n", uriString);
272-
ExecutorService readerService = Executors.newCachedThreadPool();
262+
out.printf("%n---- starting sequential (%s) ----%n%n", uriString);
273263
HttpClient client = HttpClient.newBuilder()
274264
.proxy(NO_PROXY)
275265
.followRedirects(Redirect.ALWAYS)
@@ -339,7 +329,7 @@ void testSequential(String uriString) throws Exception {
339329
} catch (Throwable throwable) {
340330
failed = throwable;
341331
} finally {
342-
failed = cleanup(client, readerService, failed);
332+
failed = cleanup(client, failed);
343333
}
344334
if (failed instanceof Exception ex) throw ex;
345335
if (failed instanceof Error e) throw e;
@@ -354,6 +344,7 @@ public void setup() throws Exception {
354344
sslContext = new SimpleSSLContext().get();
355345
if (sslContext == null)
356346
throw new AssertionError("Unexpected null sslContext");
347+
readerService = Executors.newCachedThreadPool();
357348

358349
httpTestServer = HttpTestServer.create(HTTP_1_1);
359350
httpTestServer.addHandler(new ServerRequestHandler(), "/http1/exec/");
@@ -380,6 +371,7 @@ public void teardown() throws Exception {
380371
Thread.sleep(100);
381372
AssertionError fail = TRACKER.checkShutdown(5000);
382373
try {
374+
shutdown(readerService);
383375
httpTestServer.stop();
384376
httpsTestServer.stop();
385377
http2TestServer.stop();
@@ -389,6 +381,15 @@ public void teardown() throws Exception {
389381
}
390382
}
391383

384+
static void shutdown(ExecutorService executorService) {
385+
try {
386+
executorService.shutdown();
387+
executorService.awaitTermination(2000, TimeUnit.MILLISECONDS);
388+
} catch (InterruptedException ie) {
389+
executorService.shutdownNow();
390+
}
391+
}
392+
392393
static class ServerRequestHandler implements HttpTestHandler {
393394
ConcurrentHashMap<String,String> closedRequests = new ConcurrentHashMap<>();
394395

0 commit comments

Comments
 (0)