8378163: test/jdk/java/net/httpclient/*.java: convert tests that use ITestContext to JUnit

Reviewed-by: vyazici
This commit is contained in:
Daniel Fuchs 2026-02-20 17:22:21 +00:00
parent 932f28c69b
commit c1f8209cb2
19 changed files with 979 additions and 998 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,7 +22,7 @@
*/
/**
/*
* This is not a test. Actual tests are implemented by concrete subclasses.
* The abstract class AbstractThrowingPushPromises provides a base framework
* to test what happens when push promise handlers and their
@ -62,7 +62,6 @@ import java.net.http.HttpResponse.BodySubscriber;
import java.net.http.HttpResponse.PushPromiseHandler;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@ -104,7 +103,6 @@ import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class AbstractThrowingPushPromises implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
@ -193,14 +191,9 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
@AfterAll
static final void printFailedTests() {
static void printFailedTests() {
out.println("\n=========================");
try {
// Exceptions should already have been added to FAILURES
// var failed = context.getFailedTests().getAllResults().stream()
// .collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
// FAILURES.putAll(failed);
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
if (FAILURES.isEmpty()) return;
@ -339,7 +332,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
HttpRequest req = request(uri);
BodyHandler<Stream<String>> handler =
new ThrowingBodyHandler((w) -> {},
new ThrowingBodyHandler<>((w) -> {},
BodyHandlers.ofLines());
Map<HttpRequest, CompletableFuture<HttpResponse<Stream<String>>>> pushPromises =
new ConcurrentHashMap<>();
@ -387,9 +380,9 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
}
// @Test(dataProvider = "variants")
protected void testThrowingAsStringImpl(String uri,
boolean sameClient,
Thrower thrower)
void testThrowingAsStringImpl(String uri,
boolean sameClient,
Thrower thrower)
throws Exception
{
String test = format("testThrowingAsString(%s, %b, %s)",
@ -399,7 +392,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
}
//@Test(dataProvider = "variants")
protected void testThrowingAsLinesImpl(String uri,
void testThrowingAsLinesImpl(String uri,
boolean sameClient,
Thrower thrower)
throws Exception
@ -411,9 +404,9 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
}
//@Test(dataProvider = "variants")
protected void testThrowingAsInputStreamImpl(String uri,
boolean sameClient,
Thrower thrower)
void testThrowingAsInputStreamImpl(String uri,
boolean sameClient,
Thrower thrower)
throws Exception
{
String test = format("testThrowingAsInputStream(%s, %b, %s)",
@ -424,7 +417,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
private <T,U> void testThrowing(String name, String uri, boolean sameClient,
Supplier<BodyHandler<T>> handlers,
Finisher finisher, Thrower thrower)
Finisher<T,U> finisher, Thrower thrower)
throws Exception
{
out.printf("%n%s%s%n", now(), name);
@ -438,7 +431,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
private <T,U> void testThrowing(String uri, boolean sameClient,
Supplier<BodyHandler<T>> handlers,
Finisher finisher, Thrower thrower)
Finisher<T,U> finisher, Thrower thrower)
throws Exception
{
HttpClient client = null;
@ -452,7 +445,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<T>>> promiseMap =
new ConcurrentHashMap<>();
Supplier<BodyHandler<T>> throwing = () ->
new ThrowingBodyHandler(where.select(thrower), handlers.get());
new ThrowingBodyHandler<>(where.select(thrower), handlers.get());
PushPromiseHandler<T> pushHandler = new ThrowingPromiseHandler<>(
where.select(thrower),
PushPromiseHandler.of((r) -> throwing.get(), promiseMap));
@ -540,7 +533,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
return check(w, reqURI, resp, thrower, promises, extractor);
}
private final <T> List<String> check(Where w, URI reqURI,
private <T> List<String> check(Where w, URI reqURI,
HttpResponse<T> resp,
Thrower thrower,
Map<HttpRequest, CompletableFuture<HttpResponse<T>>> promises,
@ -697,7 +690,7 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
public BodySubscriber<T> apply(HttpResponse.ResponseInfo rinfo) {
throwing.accept(Where.BODY_HANDLER);
BodySubscriber<T> subscriber = bodyHandler.apply(rinfo);
return new ThrowingBodySubscriber(throwing, subscriber);
return new ThrowingBodySubscriber<>(throwing, subscriber);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
* @library /test/lib /test/jdk/java/net/httpclient/lib
* @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters
* ReferenceTracker AggregateRequestBodyTest
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.HttpClient.log=requests,responses,errors,headers,frames
* AggregateRequestBodyTest
* @summary Tests HttpRequest.BodyPublishers::concat
@ -41,7 +41,6 @@ import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -70,40 +69,43 @@ import javax.net.ssl.SSLContext;
import jdk.test.lib.net.SimpleSSLContext;
import jdk.test.lib.net.URIBuilder;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static java.net.http.HttpClient.Version.HTTP_1_1;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class AggregateRequestBodyTest implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer http1TestServer; // HTTP/1.1 ( http )
HttpTestServer https1TestServer; // HTTPS/1.1 ( https )
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer http3TestServer; // HTTP/3 ( h3 )
URI http1URI;
URI https1URI;
URI http2URI;
URI https2URI;
URI http3URI;
private static HttpTestServer http1TestServer; // HTTP/1.1 ( http )
private static HttpTestServer https1TestServer; // HTTPS/1.1 ( https )
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3 ( h3 )
private static URI http1URI;
private static URI https1URI;
private static URI http2URI;
private static URI https2URI;
private static URI http3URI;
static final int RESPONSE_CODE = 200;
static final int ITERATION_COUNT = 4;
@ -123,8 +125,8 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -150,40 +152,40 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
try {
var failed = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
FAILURES.putAll(failed);
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
if (FAILURES.isEmpty()) return;
@ -201,7 +203,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
}
}
private URI[] uris() {
private static URI[] uris() {
return new URI[] {
http1URI,
https1URI,
@ -211,13 +213,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
};
}
static AtomicLong URICOUNT = new AtomicLong();
@DataProvider(name = "variants")
public Object[][] variants(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
return new Object[0][];
}
public static Object[][] variants() {
URI[] uris = uris();
Object[][] result = new Object[uris.length * 2][];
int i = 0;
@ -285,8 +281,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
return s;
}
@DataProvider(name = "sparseContent")
Object[][] nulls() {
static Object[][] nulls() {
return new Object[][] {
{"null array", null},
{"null element", strings((String)null)},
@ -304,8 +299,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
.collect(Collectors.toList());
}
@DataProvider(name = "contentLengths")
Object[][] contentLengths() {
static Object[][] contentLengths() {
return new Object[][] {
{-1, lengths(-1)},
{-42, lengths(-42)},
@ -332,8 +326,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
};
}
@DataProvider(name="negativeRequests")
Object[][] negativeRequests() {
static Object[][] negativeRequests() {
return new Object[][] {
{0L}, {-1L}, {-2L}, {Long.MIN_VALUE + 1L}, {Long.MIN_VALUE}
};
@ -492,31 +485,33 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
() -> new AssertionError("Should not happen!"));
}
@Test(dataProvider = "sparseContent") // checks that NPE is thrown
@ParameterizedTest // checks that NPE is thrown
@MethodSource("nulls")
public void testNullPointerException(String description, String[] content) {
checkSkip();
out.printf("%n%s-- testNullPointerException %s%n%n", now(), description);
BodyPublisher[] publishers = publishers(content);
Assert.assertThrows(NullPointerException.class, () -> BodyPublishers.concat(publishers));
Assertions.assertThrows(NullPointerException.class, () -> BodyPublishers.concat(publishers));
}
// Verifies that an empty array creates a "noBody" publisher
@Test
public void testEmpty() {
checkSkip();
out.printf("%n%s-- testEmpty%n%n", now());
BodyPublisher publisher = BodyPublishers.concat();
RequestSubscriber subscriber = new RequestSubscriber();
assertEquals(publisher.contentLength(), 0);
assertEquals(0, publisher.contentLength());
publisher.subscribe(subscriber);
subscriber.subscriptionCF.thenAccept(s -> s.request(1));
List<ByteBuffer> result = subscriber.resultCF.join();
assertEquals(result, List.of());
assertEquals(List.of(), result);
assertTrue(subscriber.items.isEmpty());
}
// verifies that error emitted by upstream publishers are propagated downstream.
@Test(dataProvider = "sparseContent") // nulls are replaced with error publisher
@ParameterizedTest // nulls are replaced with error publisher
@MethodSource("nulls")
public void testOnError(String description, String[] content) {
checkSkip();
out.printf("%n%s-- testOnError %s%n%n", now(), description);
final RequestSubscriber subscriber = new RequestSubscriber();
final PublishWithError errorPublisher;
final BodyPublisher[] publishers;
@ -556,13 +551,13 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
publisher.subscribe(subscriber);
subscriber.subscriptionCF.thenAccept(s -> s.request(Long.MAX_VALUE));
if (errorPublisher.hasErrors()) {
CompletionException ce = expectThrows(CompletionException.class,
CompletionException ce = Assertions.assertThrows(CompletionException.class,
() -> subscriber.resultCF.join());
out.println(description + ": got expected " + ce);
assertEquals(ce.getCause().getClass(), Exception.class);
assertEquals(stringFromBytes(subscriber.items.stream()) + "<error>", result);
assertEquals(Exception.class, ce.getCause().getClass());
assertEquals(result, stringFromBytes(subscriber.items.stream()) + "<error>");
} else {
assertEquals(stringFromBytes(subscriber.resultCF.join().stream()), result);
assertEquals(result, stringFromBytes(subscriber.resultCF.join().stream()));
out.println(description + ": got expected result: " + result);
}
}
@ -570,9 +565,10 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
// Verifies that if an upstream publisher has an unknown length, the
// aggregate publisher will have an unknown length as well. Otherwise
// the length should be known.
@Test(dataProvider = "sparseContent") // nulls are replaced with unknown length
@ParameterizedTest // nulls are replaced with unknown length
@MethodSource("nulls")
public void testUnknownContentLength(String description, String[] content) {
checkSkip();
out.printf("%n%s-- testUnknownContentLength %s%n%n", now(), description);
if (content == null) {
content = BODIES.toArray(String[]::new);
description = "BODIES (known length)";
@ -598,9 +594,9 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
length += content[i].length();
}
}
out.printf("testUnknownContentLength(%s): %d%n", description, length);
out.printf("%stestUnknownContentLength(%s): %d%n", now(), description, length);
BodyPublisher publisher = BodyPublishers.concat(publishers);
assertEquals(publisher.contentLength(), length,
assertEquals(length, publisher.contentLength(),
description.replace("null", "length(-1)"));
}
@ -611,9 +607,10 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
return x.getCause();
}
@Test(dataProvider = "negativeRequests")
@ParameterizedTest
@MethodSource("negativeRequests")
public void testNegativeRequest(long n) {
checkSkip();
out.printf("%n%s-- testNegativeRequest %s%n%n", now(), n);
assert n <= 0 : "test for negative request called with n > 0 : " + n;
BodyPublisher[] publishers = ContentLengthPublisher.of(List.of(1L, 2L, 3L));
BodyPublisher publisher = BodyPublishers.concat(publishers);
@ -621,7 +618,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
publisher.subscribe(subscriber);
Subscription subscription = subscriber.subscriptionCF.join();
subscription.request(n);
CompletionException expected = expectThrows(CE, () -> subscriber.resultCF.join());
CompletionException expected = Assertions.assertThrows(CE, () -> subscriber.resultCF.join());
Throwable cause = completionCause(expected);
if (cause instanceof IllegalArgumentException) {
System.out.printf("Got expected IAE for %d: %s%n", n, cause);
@ -637,7 +634,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
@Test
public void testPositiveRequests() {
checkSkip();
out.printf("%n%s-- testPositiveRequests%n%n", now());
// A composite array of publishers
BodyPublisher[] publishers = Stream.of(
Stream.of(ofStrings("Lorem", " ", "ipsum", " ")),
@ -657,7 +654,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
List<ByteBuffer> list1 = requestSubscriber1.resultCF().join();
assertTrue(requestSubscriber1.resultCF().isDone());
String result1 = stringFromBytes(list1.stream());
assertEquals(result1, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
assertEquals("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", result1);
System.out.println("Got expected sentence with one request: \"%s\"".formatted(result1));
// Test that we can split our requests call any which way we want
@ -675,16 +672,17 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
List<ByteBuffer> list2 = requestSubscriber2.resultCF().join();
assertTrue(requestSubscriber2.resultCF().isDone());
String result2 = stringFromBytes(list2.stream());
assertEquals(result2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
assertEquals("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", result2);
System.out.println("Got expected sentence with 4 requests: \"%s\"".formatted(result1));
}
@Test(dataProvider = "contentLengths")
@ParameterizedTest
@MethodSource("contentLengths")
public void testContentLength(long expected, List<Long> lengths) {
checkSkip();
out.printf("%n%s-- testContentLength expected=%s %s%n%n", now(), expected, lengths);
BodyPublisher[] publishers = ContentLengthPublisher.of(lengths);
BodyPublisher aggregate = BodyPublishers.concat(publishers);
assertEquals(aggregate.contentLength(), expected,
assertEquals(expected, aggregate.contentLength(),
"Unexpected result for %s".formatted(lengths));
}
@ -692,14 +690,13 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
// publishers are no longer subscribed etc...
@Test
public void testCancel() {
checkSkip();
out.printf("%n%s-- testCancel%n%n", now());
BodyPublisher[] publishers = BODIES.stream()
.map(BodyPublishers::ofString)
.toArray(BodyPublisher[]::new);
BodyPublisher publisher = BodyPublishers.concat(publishers);
assertEquals(publisher.contentLength(),
BODIES.stream().mapToInt(String::length).sum());
assertEquals(BODIES.stream().mapToInt(String::length).sum(), publisher.contentLength());
Map<RequestSubscriber, String> subscribers = new LinkedHashMap<>();
for (int n=0; n < BODIES.size(); n++) {
@ -731,7 +728,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
// subscription was cancelled, so nothing should be received...
try {
TimeoutException x = Assert.expectThrows(TimeoutException.class,
TimeoutException x = Assertions.assertThrows(TimeoutException.class,
() -> any.get(5, TimeUnit.SECONDS));
out.println("Got expected " + x);
} finally {
@ -742,8 +739,8 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
subscribers.get(rs), rs.resultCF));
}
Consumer<RequestSubscriber> check = (rs) -> {
Assert.assertTrue(rs.items.isEmpty(), subscribers.get(rs) + " has items");
Assert.assertFalse(rs.resultCF.isDone(), subscribers.get(rs) + " was not cancelled");
assertTrue(rs.items.isEmpty(), subscribers.get(rs) + " has items");
assertFalse(rs.resultCF.isDone(), subscribers.get(rs) + " was not cancelled");
out.println(subscribers.get(rs) + ": PASSED");
};
subscribers.keySet().stream().forEach(check);
@ -752,13 +749,12 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
// Verifies that cancelling the subscription is propagated downstream
@Test
public void testCancelSubscription() {
checkSkip();
out.printf("%n%s-- testCancelSubscription%n%n", now());
PublishWithError upstream = new PublishWithError(BODIES, BODIES.size(),
() -> new AssertionError("should not come here"));
BodyPublisher publisher = BodyPublishers.concat(upstream);
assertEquals(publisher.contentLength(),
BODIES.stream().mapToInt(String::length).sum());
assertEquals(BODIES.stream().mapToInt(String::length).sum(), publisher.contentLength());
Map<RequestSubscriber, String> subscribers = new LinkedHashMap<>();
for (int n=0; n < BODIES.size(); n++) {
@ -793,7 +789,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
// subscription was cancelled, so nothing should be received...
try {
TimeoutException x = Assert.expectThrows(TimeoutException.class,
TimeoutException x = Assertions.assertThrows(TimeoutException.class,
() -> any.get(5, TimeUnit.SECONDS));
out.println("Got expected " + x);
} finally {
@ -804,17 +800,19 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
subscribers.get(rs), rs.resultCF));
}
Consumer<RequestSubscriber> check = (rs) -> {
Assert.assertTrue(rs.items.isEmpty(), subscribers.get(rs) + " has items");
Assert.assertFalse(rs.resultCF.isDone(), subscribers.get(rs) + " was not cancelled");
assertTrue(rs.items.isEmpty(), subscribers.get(rs) + " has items");
assertFalse(rs.resultCF.isDone(), subscribers.get(rs) + " was not cancelled");
out.println(subscribers.get(rs) + ": PASSED");
};
subscribers.keySet().stream().forEach(check);
}
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
public void test(URI uri, HttpClient.Version version, boolean sameClient) throws Exception {
checkSkip();
out.printf("%n%s-- test sameClient=%s, version=%s, uri=%s%n%n",
now(), sameClient, version, uri);
System.out.printf("Request to %s (sameClient: %s)%n", uri, sameClient);
System.err.printf("Request to %s (sameClient: %s)%n", uri, sameClient);
@ -838,13 +836,13 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
int expectedResponse = RESPONSE_CODE;
if (response.statusCode() != expectedResponse)
throw new RuntimeException("wrong response code " + Integer.toString(response.statusCode()));
assertEquals(response.body(), BODIES.stream().collect(Collectors.joining()));
assertEquals(BODIES.stream().collect(Collectors.joining()), response.body());
}
if (!sameClient) client.close();
System.out.println("test: DONE");
}
private URI buildURI(String scheme, String path, int port) {
private static URI buildURI(String scheme, String path, int port) {
return URIBuilder.newBuilder()
.scheme(scheme)
.loopback()
@ -853,8 +851,8 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
.buildUnchecked();
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
HttpTestHandler handler = new HttpTestEchoHandler();
http1TestServer = HttpTestServer.create(HTTP_1_1);
http1TestServer.addHandler(handler, "/http1/echo/");
@ -884,8 +882,8 @@ public class AggregateRequestBodyTest implements HttpServerAdapters {
http3TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
String sharedClientName =
sharedClient == null ? null : sharedClient.toString();
sharedClient.close();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
* @build jdk.test.lib.net.SimpleSSLContext
* jdk.httpclient.test.lib.common.HttpServerAdapters
* ReferenceTracker
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.HttpClient.log=requests,responses,errors
* BasicHTTP2Test
* @summary Basic HTTP/2 test when HTTP/3 is requested
@ -44,37 +44,40 @@ import java.net.http.HttpRequest;
import java.net.http.HttpRequest.Builder;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLContext;
import jdk.test.lib.net.SimpleSSLContext;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import org.testng.ITestContext;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
public class BasicHTTP2Test implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
String https2URI;
DatagramSocket udp;
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static String https2URI;
private static DatagramSocket udp;
// a shared executor helps reduce the amount of threads created by the test
static final Executor executor = new TestExecutor(Executors.newCachedThreadPool());
@ -91,8 +94,7 @@ public class BasicHTTP2Test implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -118,20 +120,37 @@ public class BasicHTTP2Test implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
var x = new SkipException("Skipping: some test failed");
x.setStackTrace(new StackTraceElement[0]);
throw x;
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static final void printFailedTests() {
out.println("\n=========================");
try {
@ -152,14 +171,6 @@ public class BasicHTTP2Test implements HttpServerAdapters {
}
}
private String[] uris() {
return new String[] {
https2URI,
};
}
static AtomicLong URICOUNT = new AtomicLong();
private HttpClient makeNewClient() {
clientCount.incrementAndGet();
HttpClient client = HttpClient.newBuilder()
@ -170,37 +181,6 @@ public class BasicHTTP2Test implements HttpServerAdapters {
return TRACKER.track(client);
}
HttpClient newHttpClient(boolean share) {
if (!share) return makeNewClient();
HttpClient shared = sharedClient;
if (shared != null) return shared;
synchronized (this) {
shared = sharedClient;
if (shared == null) {
shared = sharedClient = makeNewClient();
}
return shared;
}
}
static void checkStatus(int expected, int found) throws Exception {
if (expected != found) {
System.err.printf ("Test failed: wrong status code %d/%d\n",
expected, found);
throw new RuntimeException("Test failed");
}
}
static void checkStrings(String expected, String found) throws Exception {
if (!expected.equals(found)) {
System.err.printf ("Test failed: wrong string %s/%s\n",
expected, found);
throw new RuntimeException("Test failed");
}
}
@Test
public void testH2() throws Exception {
@ -220,8 +200,8 @@ public class BasicHTTP2Test implements HttpServerAdapters {
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
out.println("Response #1: " + response);
out.println("Version #1: " + response.version());
assertEquals(response.statusCode(), 200, "first response status");
assertEquals(response.version(), HTTP_2, "first response version");
assertEquals(200, response.statusCode(), "first response status");
assertEquals(HTTP_2, response.version(), "first response version");
Thread.sleep(1000);
@ -232,16 +212,15 @@ public class BasicHTTP2Test implements HttpServerAdapters {
response = client.send(request, BodyHandlers.ofString());
out.println("Response #2: " + response);
out.println("Version #2: " + response.version());
assertEquals(response.statusCode(), 200, "second response status");
assertEquals(response.version(), HTTP_2, "second response version");
assertEquals(200, response.statusCode(), "second response status");
assertEquals(HTTP_2, response.version(), "second response version");
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
// HTTP/2
HttpTestHandler handler = new Handler();
HttpTestHandler h3Handler = new Handler();
https2TestServer = HttpTestServer.create(HTTP_2, sslContext);
https2TestServer.addHandler(handler, "/https2/test204/");
@ -259,11 +238,8 @@ public class BasicHTTP2Test implements HttpServerAdapters {
https2TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
String sharedClientName =
sharedClient == null ? null : sharedClient.toString();
sharedClient = null;
@AfterAll
public static void teardown() throws Exception {
Thread.sleep(100);
AssertionError fail = TRACKER.check(500);
try {
@ -271,10 +247,7 @@ public class BasicHTTP2Test implements HttpServerAdapters {
https2TestServer.stop();
} finally {
if (fail != null) {
if (sharedClientName != null) {
System.err.println("Shared client name is: " + sharedClientName);
}
throw fail;
throw fail;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,6 @@ import java.net.http.HttpRequest;
import java.net.http.HttpRequest.Builder;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@ -40,28 +39,32 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLContext;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.httpclient.test.lib.http2.Http2TestServer;
import jdk.internal.net.quic.QuicVersion;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static org.testng.Assert.*;
import static org.junit.jupiter.api.Assertions.*;
import static java.lang.System.out;
import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/*
* @test
@ -70,7 +73,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC;
* jdk.httpclient.test.lib.common.HttpServerAdapters
* ReferenceTracker
* jdk.httpclient.test.lib.quic.QuicStandaloneServer
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.HttpClient.log=requests,responses,errors
* -Djavax.net.debug=all
* BasicHTTP3Test
@ -79,20 +82,20 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC;
public class BasicHTTP3Test implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
String https2URI;
HttpTestServer h3TestServer; // HTTP/2 ( h2 + h3)
String h3URI;
HttpTestServer h3qv2TestServer; // HTTP/2 ( h2 + h3 on Quic v2, incompatible nego)
String h3URIQv2;
HttpTestServer h3qv2CTestServer; // HTTP/2 ( h2 + h3 on Quic v2, compatible nego)
String h3URIQv2C;
HttpTestServer h3mtlsTestServer; // HTTP/2 ( h2 + h3), h3 requires client cert
String h3mtlsURI;
HttpTestServer h3TestServerWithRetry; // h3
String h3URIRetry;
HttpTestServer h3TestServerWithTLSHelloRetry; // h3
String h3URITLSHelloRetry;
static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
static String https2URI;
static HttpTestServer h3TestServer; // HTTP/2 ( h2 + h3)
static String h3URI;
static HttpTestServer h3qv2TestServer; // HTTP/2 ( h2 + h3 on Quic v2, incompatible nego)
static String h3URIQv2;
static HttpTestServer h3qv2CTestServer; // HTTP/2 ( h2 + h3 on Quic v2, compatible nego)
static String h3URIQv2C;
static HttpTestServer h3mtlsTestServer; // HTTP/2 ( h2 + h3), h3 requires client cert
static String h3mtlsURI;
static HttpTestServer h3TestServerWithRetry; // h3
static String h3URIRetry;
static HttpTestServer h3TestServerWithTLSHelloRetry; // h3
static String h3URITLSHelloRetry;
static final int ITERATION_COUNT = 4;
// a shared executor helps reduce the amount of threads created by the test
@ -109,8 +112,8 @@ public class BasicHTTP3Test implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -136,21 +139,38 @@ public class BasicHTTP3Test implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
var x = new SkipException("Skipping: some test failed");
x.setStackTrace(new StackTraceElement[0]);
throw x;
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests() {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
try {
out.printf("%n%sCreated %d clients%n",
@ -170,18 +190,14 @@ public class BasicHTTP3Test implements HttpServerAdapters {
}
}
private String[] uris() {
private static String[] uris() {
return new String[] {
https2URI,
h3URI
};
}
@DataProvider(name = "variants")
public Object[][] variants(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
return new Object[0][];
}
public static Object[][] variants() {
String[] uris = uris();
Object[][] result = new Object[uris.length * 2 * 2][];
int i = 0;
@ -196,11 +212,7 @@ public class BasicHTTP3Test implements HttpServerAdapters {
return result;
}
@DataProvider(name = "h3URIs")
public Object[][] versions(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
return new Object[0][];
}
public static Object[][] versions() {
Object[][] result = {
{h3URI}, {h3URIRetry},
{h3URIQv2}, {h3URIQv2C},
@ -233,9 +245,11 @@ public class BasicHTTP3Test implements HttpServerAdapters {
}
}
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
public void test(String uri, boolean sameClient, Optional<Version> version) throws Exception {
System.out.println("Request to " + uri);
System.out.printf("%n%s-- test version=%s, sameClient=%s, uri=%s%n%n",
now(), version, sameClient, uri);
HttpClient client = newHttpClient(sameClient);
@ -267,8 +281,10 @@ public class BasicHTTP3Test implements HttpServerAdapters {
System.out.println("test: DONE");
}
@Test(dataProvider = "h3URIs")
@ParameterizedTest
@MethodSource("versions")
public void testH3(final String h3URI) throws Exception {
System.out.printf("%n%s-- testH3 h3URI=%s%n%n", now(), h3URI);
HttpClient client = makeNewClient();
URI uri = URI.create(h3URI);
Builder builder = HttpRequest.newBuilder(uri)
@ -278,17 +294,17 @@ public class BasicHTTP3Test implements HttpServerAdapters {
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
out.println("Response #1: " + response);
out.println("Version #1: " + response.version());
assertEquals(response.statusCode(), 200, "first response status");
assertEquals(response.version(), HTTP_2, "first response version");
assertEquals(200, response.statusCode(), "first response status");
assertEquals(HTTP_2, response.version(), "first response version");
request = builder.version(Version.HTTP_3).build();
response = client.send(request, BodyHandlers.ofString());
out.println("Response #2: " + response);
out.println("Version #2: " + response.version());
assertEquals(response.statusCode(), 200, "second response status");
assertEquals(response.version(), Version.HTTP_3, "second response version");
assertEquals(200, response.statusCode(), "second response status");
assertEquals(Version.HTTP_3, response.version(), "second response version");
if (h3URI == h3mtlsURI) {
if (h3URI.equals(h3mtlsURI)) {
assertNotNull(response.sslSession().get().getLocalCertificates());
} else {
assertNull(response.sslSession().get().getLocalCertificates());
@ -303,6 +319,7 @@ public class BasicHTTP3Test implements HttpServerAdapters {
// verify that the client handles HTTP/3 reset stream correctly
@Test
public void testH3Reset() throws Exception {
System.out.printf("%n%s-- testH3Reset uri=%s%n%n", now(), h3URI);
HttpClient client = makeNewClient();
URI uri = URI.create(h3URI);
Builder builder = HttpRequest.newBuilder(uri)
@ -312,8 +329,8 @@ public class BasicHTTP3Test implements HttpServerAdapters {
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
out.println("Response #1: " + response);
out.println("Version #1: " + response.version());
assertEquals(response.statusCode(), 200, "first response status");
assertEquals(response.version(), HTTP_2, "first response version");
assertEquals(200, response.statusCode(), "first response status");
assertEquals(HTTP_2, response.version(), "first response version");
// instruct the server side handler to throw an exception
// that then causes the test server to reset the stream
@ -341,8 +358,8 @@ public class BasicHTTP3Test implements HttpServerAdapters {
if (error != null) throw error;
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
https2TestServer = HttpTestServer.create(HTTP_2, sslContext);
https2TestServer.addHandler(new Handler(), "/https2/test/");
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/test/x";
@ -360,7 +377,7 @@ public class BasicHTTP3Test implements HttpServerAdapters {
.enableH3AltServiceOnEphemeralPortWithVersion(QuicVersion.QUIC_V2, false);
h3qv2TestServer = HttpTestServer.of(h2q2Server);
h3qv2TestServer.addHandler(h3Handler, "/h3/testH3/");
h3URIQv2 = "https://" + h3qv2TestServer.serverAuthority() + "/h3/testH3/h3qv2";;
h3URIQv2 = "https://" + h3qv2TestServer.serverAuthority() + "/h3/testH3/h3qv2";
assertTrue(h3qv2TestServer.canHandle(HTTP_2, Version.HTTP_3), "Server was expected" +
" to handle both HTTP2 and HTTP3, but doesn't");
@ -369,7 +386,7 @@ public class BasicHTTP3Test implements HttpServerAdapters {
.enableH3AltServiceOnEphemeralPortWithVersion(QuicVersion.QUIC_V2, true);
h3qv2CTestServer = HttpTestServer.of(h2q2CServer);
h3qv2CTestServer.addHandler(h3Handler, "/h3/testH3/");
h3URIQv2C = "https://" + h3qv2CTestServer.serverAuthority() + "/h3/testH3/h3qv2c";;
h3URIQv2C = "https://" + h3qv2CTestServer.serverAuthority() + "/h3/testH3/h3qv2c";
assertTrue(h3qv2CTestServer.canHandle(HTTP_2, Version.HTTP_3), "Server was expected" +
" to handle both HTTP2 and HTTP3, but doesn't");
@ -411,8 +428,8 @@ public class BasicHTTP3Test implements HttpServerAdapters {
h3TestServerWithTLSHelloRetry.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
System.err.println("=======================================================");
System.err.println(" Tearing down test");
System.err.println("=======================================================");

View File

@ -29,7 +29,7 @@
* @key randomness
* @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext
* ReferenceTracker CancelRequestTest
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.enableAllMethodRetry=true
* CancelRequestTest
*/
@ -38,15 +38,6 @@
import jdk.internal.net.http.common.OperationTrackers.Tracker;
import jdk.test.lib.RandomFactory;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
@ -61,7 +52,6 @@ import java.net.http.HttpOption.Http3DiscoveryMode;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandler;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@ -76,7 +66,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import static java.lang.System.out;
@ -85,10 +74,21 @@ import static java.net.http.HttpClient.Version.*;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class CancelRequestTest implements HttpServerAdapters {
@ -97,19 +97,19 @@ public class CancelRequestTest implements HttpServerAdapters {
= new ConcurrentHashMap<>();
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer h2h3TestServer; // HTTP/3 ( h2 + h3 )
HttpTestServer h3TestServer; // HTTP/3 ( h3 )
String httpURI;
String httpsURI;
String http2URI;
String https2URI;
String h2h3URI;
String h2h3Head;
String h3URI;
private static HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
private static HttpTestServer httpsTestServer; // HTTPS/1.1
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer h2h3TestServer; // HTTP/3 ( h2 + h3 )
private static HttpTestServer h3TestServer; // HTTP/3 ( h3 )
private static String httpURI;
private static String httpsURI;
private static String http2URI;
private static String https2URI;
private static String h2h3URI;
private static String h2h3Head;
private static String h3URI;
static final long SERVER_LATENCY = 75;
static final int MAX_CLIENT_DELAY = 75;
@ -130,8 +130,8 @@ public class CancelRequestTest implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -157,38 +157,39 @@ public class CancelRequestTest implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
var failed = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(CancelRequestTest::name, ITestResult::getThrowable));
FAILURES.putAll(failed);
try {
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
@ -206,7 +207,7 @@ public class CancelRequestTest implements HttpServerAdapters {
}
}
private String[] uris() {
private static String[] uris() {
return new String[] {
httpURI,
httpsURI,
@ -217,8 +218,7 @@ public class CancelRequestTest implements HttpServerAdapters {
};
}
@DataProvider(name = "asyncurls")
public Object[][] asyncurls() {
public static Object[][] asyncurls() {
String[] uris = uris();
Object[][] result = new Object[uris.length * 2 * 3][];
//Object[][] result = new Object[uris.length][];
@ -238,8 +238,7 @@ public class CancelRequestTest implements HttpServerAdapters {
return result;
}
@DataProvider(name = "urls")
public Object[][] alltests() {
public static Object[][] alltests() {
String[] uris = uris();
Object[][] result = new Object[uris.length * 2][];
//Object[][] result = new Object[uris.length][];
@ -327,7 +326,7 @@ public class CancelRequestTest implements HttpServerAdapters {
.HEAD()
.build();
var resp = client.send(request, BodyHandlers.discarding());
assertEquals(resp.statusCode(), 200);
assertEquals(200, resp.statusCode());
}
private static void releaseLatches() {
@ -348,10 +347,10 @@ public class CancelRequestTest implements HttpServerAdapters {
return latch;
}
@Test(dataProvider = "asyncurls")
@ParameterizedTest
@MethodSource("asyncurls")
public void testGetSendAsync(String uri, boolean sameClient, boolean mayInterruptIfRunning)
throws Exception {
checkSkip();
HttpClient client = null;
uri = uri + "/get";
out.printf("%n%s testGetSendAsync(%s, %b, %b)%n", now(), uri, sameClient, mayInterruptIfRunning);
@ -386,7 +385,7 @@ public class CancelRequestTest implements HttpServerAdapters {
out.println("cf2 after cancel: " + cf2);
try {
String body = cf2.get().body();
assertEquals(body, String.join("", BODY.split("\\|")));
assertEquals(String.join("", BODY.split("\\|")), body);
throw new AssertionError("Expected CancellationException not received");
} catch (ExecutionException x) {
out.println(now() + "Got expected exception: " + x);
@ -409,7 +408,7 @@ public class CancelRequestTest implements HttpServerAdapters {
// completed yet - so wait for it here...
try {
String body = response.get().body();
assertEquals(body, String.join("", BODY.split("\\|")));
assertEquals(String.join("", BODY.split("\\|")), body);
if (mayInterruptIfRunning) {
// well actually - this could happen... In which case we'll need to
// increase the latency in the server handler...
@ -448,10 +447,10 @@ public class CancelRequestTest implements HttpServerAdapters {
assertTrue(response.isDone());
assertFalse(response.isCancelled());
assertEquals(cf1.isCancelled(), hasCancellationException);
assertEquals(hasCancellationException, cf1.isCancelled());
assertTrue(cf2.isDone());
assertFalse(cf2.isCancelled());
assertEquals(latch.getCount(), 0);
assertEquals(0, latch.getCount());
var error = TRACKER.check(tracker, 1000,
(t) -> t.getOutstandingOperations() > 0 || t.getOutstandingSubscribers() > 0,
@ -464,10 +463,10 @@ public class CancelRequestTest implements HttpServerAdapters {
if (!sameClient) client.close();
}
@Test(dataProvider = "asyncurls")
@ParameterizedTest
@MethodSource("asyncurls")
public void testPostSendAsync(String uri, boolean sameClient, boolean mayInterruptIfRunning)
throws Exception {
checkSkip();
uri = uri + "/post";
HttpClient client = null;
out.printf("%n%s testPostSendAsync(%s, %b, %b)%n", now(), uri, sameClient, mayInterruptIfRunning);
@ -521,7 +520,7 @@ public class CancelRequestTest implements HttpServerAdapters {
out.println("cf2 after cancel: " + cf2);
try {
String body = cf2.get().body();
assertEquals(body, String.join("", BODY.split("\\|")));
assertEquals(String.join("", BODY.split("\\|")), body);
throw new AssertionError("Expected CancellationException not received");
} catch (ExecutionException x) {
out.println(now() + "Got expected exception: " + x);
@ -544,7 +543,7 @@ public class CancelRequestTest implements HttpServerAdapters {
// completed yet - so wait for it here...
try {
String body = response.get().body();
assertEquals(body, String.join("", BODY.split("\\|")));
assertEquals(String.join("", BODY.split("\\|")), body);
if (mayInterruptIfRunning) {
// well actually - this could happen... In which case we'll need to
// increase the latency in the server handler...
@ -577,10 +576,10 @@ public class CancelRequestTest implements HttpServerAdapters {
assertTrue(response.isDone());
assertFalse(response.isCancelled());
assertEquals(cf1.isCancelled(), hasCancellationException);
assertEquals(hasCancellationException, cf1.isCancelled());
assertTrue(cf2.isDone());
assertFalse(cf2.isCancelled());
assertEquals(latch.getCount(), 0);
assertEquals(0, latch.getCount());
var error = TRACKER.check(tracker, 1000,
(t) -> t.getOutstandingOperations() > 0 || t.getOutstandingSubscribers() > 0,
@ -593,10 +592,10 @@ public class CancelRequestTest implements HttpServerAdapters {
if (!sameClient) client.close();
}
@Test(dataProvider = "urls")
@ParameterizedTest
@MethodSource("alltests")
public void testPostInterrupt(String uri, boolean sameClient)
throws Exception {
checkSkip();
HttpClient client = null;
out.printf("%n%s testPostInterrupt(%s, %b)%n", now(), uri, sameClient);
for (int i=0; i< ITERATION_COUNT; i++) {
@ -661,7 +660,7 @@ public class CancelRequestTest implements HttpServerAdapters {
} else {
assert failed == null;
out.println(now() + req.uri() + ": got body: " + body);
assertEquals(body, String.join("", BODY.split("\\|")));
assertEquals(String.join("", BODY.split("\\|")), body);
}
out.println(now() + "next iteration");
@ -678,8 +677,8 @@ public class CancelRequestTest implements HttpServerAdapters {
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
// HTTP/1.1
HttpTestHandler h1_chunkHandler = new HTTPSlowHandler();
httpTestServer = HttpTestServer.create(HTTP_1_1);
@ -721,8 +720,8 @@ public class CancelRequestTest implements HttpServerAdapters {
h3TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
String sharedClientName =
sharedClient == null ? null : sharedClient.toString();
sharedClient = null;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,19 +29,10 @@
* @library /test/lib /test/jdk/java/net/httpclient/lib
* @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext
* ReferenceTracker CancelStreamedBodyTest
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* CancelStreamedBodyTest
*/
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
@ -53,7 +44,6 @@ import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -61,7 +51,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
@ -72,23 +61,34 @@ import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class CancelStreamedBodyTest implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer http3TestServer; // HTTP/3 ( h3 )
String httpURI;
String httpsURI;
String http2URI;
String https2URI;
String https3URI;
private static HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
private static HttpTestServer httpsTestServer; // HTTPS/1.1
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3 ( h3 )
private static String httpURI;
private static String httpsURI;
private static String http2URI;
private static String https2URI;
private static String https3URI;
static final long SERVER_LATENCY = 75;
static final int ITERATION_COUNT = 3;
@ -108,8 +108,8 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -135,38 +135,40 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
var failed = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
FAILURES.putAll(failed);
try {
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
@ -184,7 +186,7 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
}
}
private String[] uris() {
private static String[] uris() {
return new String[] {
https3URI,
httpURI,
@ -195,8 +197,7 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
}
@DataProvider(name = "urls")
public Object[][] alltests() {
public static Object[][] alltests() {
String[] uris = uris();
Object[][] result = new Object[uris.length * 2][];
int i = 0;
@ -265,10 +266,10 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
final static String BODY = "Some string |\n that ?\n can |\n be split ?\n several |\n ways.";
@Test(dataProvider = "urls")
@ParameterizedTest
@MethodSource("alltests")
public void testAsLines(String uri, boolean sameClient)
throws Exception {
checkSkip();
HttpClient client = null;
uri = uri + "/testAsLines";
out.printf("%n%s testAsLines(%s, %b)%n", now(), uri, sameClient);
@ -284,8 +285,8 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
for (int j = 0; j < 2; j++) {
try (Stream<String> body = client.send(req, BodyHandlers.ofLines()).body()) {
lines = body.limit(j).toList();
assertEquals(lines, BODY.replaceAll("\\||\\?", "")
.lines().limit(j).toList());
assertEquals(BODY.replaceAll("\\||\\?", "")
.lines().limit(j).toList(), lines);
}
// Only check our still alive client for outstanding operations
// and outstanding subscribers here: it should have none.
@ -306,10 +307,10 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
}
}
@Test(dataProvider = "urls")
@ParameterizedTest
@MethodSource("alltests")
public void testInputStream(String uri, boolean sameClient)
throws Exception {
checkSkip();
HttpClient client = null;
uri = uri + "/testInputStream";
out.printf("%n%s testInputStream(%s, %b)%n", now(), uri, sameClient);
@ -326,7 +327,7 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
try (InputStream is = client.send(req, BodyHandlers.ofInputStream()).body()) {
for (int k = 0; k < j; k++) {
read = is.read();
assertEquals(read, BODY.charAt(k));
assertEquals(BODY.charAt(k), read);
}
}
// Only check our still alive client for outstanding operations
@ -350,8 +351,8 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
// HTTP/1.1
HttpTestHandler h1_chunkHandler = new HTTPSlowHandler();
httpTestServer = HttpTestServer.create(HTTP_1_1);
@ -385,8 +386,8 @@ public class CancelStreamedBodyTest implements HttpServerAdapters {
http3TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
String sharedClientName =
sharedClient == null ? null : sharedClient.toString();
sharedClient = null;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,7 @@
* @library /test/lib /test/jdk/java/net/httpclient/lib
* @build DigestEchoServer ForbiddenHeadTest jdk.httpclient.test.lib.common.HttpServerAdapters
* jdk.test.lib.net.SimpleSSLContext
* @run testng/othervm
* @run junit/othervm
* -Djdk.http.auth.tunneling.disabledSchemes
* -Djdk.httpclient.HttpClient.log=headers,requests
* -Djdk.internal.httpclient.debug=true
@ -36,15 +36,6 @@
*/
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
@ -61,7 +52,6 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
@ -81,27 +71,40 @@ import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.testng.Assert.assertEquals;
import org.junit.jupiter.api.AfterAll;
import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuilderForH3;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class ForbiddenHeadTest implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer httpTestServer; // HTTP/1.1
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer http3TestServer; // HTTP/3 ( h3 )
DigestEchoServer.TunnelingProxy proxy;
DigestEchoServer.TunnelingProxy authproxy;
String httpURI;
String httpsURI;
String http2URI;
String https2URI;
String https3URI;
HttpClient authClient;
HttpClient noAuthClient;
private static HttpTestServer httpTestServer; // HTTP/1.1
private static HttpTestServer httpsTestServer; // HTTPS/1.1
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3 ( h3 )
private static DigestEchoServer.TunnelingProxy proxy;
private static DigestEchoServer.TunnelingProxy authproxy;
private static String httpURI;
private static String httpsURI;
private static String http2URI;
private static String https2URI;
private static String https3URI;
private static HttpClient authClient;
private static HttpClient noAuthClient;
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
static final long SLEEP_AFTER_TEST = 0; // milliseconds
static final int ITERATIONS = 3;
static final Executor executor = new TestExecutor(Executors.newCachedThreadPool());
@ -142,34 +145,39 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
try {
// Exceptions should already have been added to FAILURES
@ -201,8 +209,7 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
static final String MESSAGE = "Unauthorized";
@DataProvider(name = "all")
public Object[][] allcases() {
public static Object[][] allcases() {
List<Object[]> result = new ArrayList<>();
for (boolean useAuth : List.of(true, false)) {
for (boolean async : List.of(true, false)) {
@ -226,8 +233,6 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
return result.toArray(new Object[0][0]);
}
static final AtomicLong requestCounter = new AtomicLong();
static final Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
@ -237,9 +242,9 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
static final AtomicLong sleepCount = new AtomicLong();
@Test(dataProvider = "all")
@ParameterizedTest
@MethodSource("allcases")
void test(String uriString, int code, boolean async, boolean useAuth) throws Throwable {
checkSkip();
HttpClient client = useAuth ? authClient : noAuthClient;
var name = String.format("test(%s, %d, %s, %s)", uriString, code, async ? "async" : "sync",
client.authenticator().isPresent() ? "authClient" : "noAuthClient");
@ -318,23 +323,23 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
out.println(" Got response: " + response);
assertEquals(response.statusCode(), forbidden? FORBIDDEN : code);
assertEquals(response.body(), expectedValue == null ? null : "");
assertEquals(response.headers().firstValue("X-value"), Optional.ofNullable(expectedValue));
assertEquals(forbidden? FORBIDDEN : code, response.statusCode());
assertEquals(expectedValue == null ? null : "", response.body());
assertEquals(Optional.ofNullable(expectedValue), response.headers().firstValue("X-value"));
// when the CONNECT request fails, its body is discarded - but
// the response header may still contain its content length.
// don't check content length in that case.
if (expectedValue != null) {
String clen = String.valueOf(expectedValue.getBytes(UTF_8).length);
assertEquals(response.headers().firstValue("Content-Length"), Optional.of(clen));
assertEquals(Optional.of(clen), response.headers().firstValue("Content-Length"));
}
}
// -- Infrastructure
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
httpTestServer = HttpTestServer.create(HTTP_1_1);
httpTestServer.addHandler(new UnauthorizedHandler(), "/http1/");
httpTestServer.addHandler(new UnauthorizedHandler(), "/http2/proxy/");
@ -357,7 +362,7 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
proxy = DigestEchoServer.createHttpsProxyTunnel(DigestEchoServer.HttpAuthSchemeType.NONE);
authproxy = DigestEchoServer.createHttpsProxyTunnel(DigestEchoServer.HttpAuthSchemeType.BASIC);
authClient = TRACKER.track(newClientBuilderForH3()
authClient = TRACKER.track(createClientBuilderForH3()
.proxy(TestProxySelector.of(proxy, authproxy, httpTestServer))
.sslContext(sslContext)
.executor(executor)
@ -365,7 +370,7 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
.build());
clientCount.incrementAndGet();
noAuthClient = TRACKER.track(newClientBuilderForH3()
noAuthClient = TRACKER.track(createClientBuilderForH3()
.proxy(TestProxySelector.of(proxy, authproxy, httpTestServer))
.sslContext(sslContext)
.executor(executor)
@ -384,8 +389,8 @@ public class ForbiddenHeadTest implements HttpServerAdapters {
serverCount.incrementAndGet();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
authClient = noAuthClient = null;
Thread.sleep(100);
AssertionError fail = TRACKER.check(1500);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -43,7 +43,6 @@ import jdk.internal.net.http.common.Utils;
import jdk.test.lib.net.SimpleSSLContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@ -63,19 +62,18 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
* jdk.httpclient.test.lib.common.HttpServerAdapters
* @run junit/othervm -Djdk.internal.httpclient.debug=true HeadersLowerCaseTest
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HeadersLowerCaseTest implements HttpServerAdapters {
private static Set<String> REQUEST_HEADERS;
private HttpTestServer h2server;
private HttpTestServer h3server;
private String h2ReqURIBase;
private String h3ReqURIBase;
private static HttpTestServer h2server;
private static HttpTestServer h3server;
private static String h2ReqURIBase;
private static String h3ReqURIBase;
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
@BeforeAll
public void beforeAll() throws Exception {
public static void beforeAll() throws Exception {
h2server = HttpTestServer.create(HTTP_2, sslContext);
h2server.start();
h2ReqURIBase = "https://" + h2server.serverAuthority();
@ -100,7 +98,7 @@ public class HeadersLowerCaseTest implements HttpServerAdapters {
}
@AfterAll
public void afterAll() throws Exception {
public static void afterAll() throws Exception {
if (h2server != null) {
h2server.stop();
}
@ -157,14 +155,14 @@ public class HeadersLowerCaseTest implements HttpServerAdapters {
}
}
private Stream<Arguments> params() throws Exception {
private static Stream<Arguments> params() throws Exception {
return Stream.of(
Arguments.of(HTTP_2, new URI(h2ReqURIBase + "/h2verifyReqHeaders")),
Arguments.of(Version.HTTP_3, new URI(h3ReqURIBase + "/h3verifyReqHeaders")));
}
/**
* Issues a HTTP/2 or HTTP/3 request with header names of varying case (some in lower,
* Issues an HTTP/2 or HTTP/3 request with header names of varying case (some in lower,
* some mixed, some upper case) and expects that the client internally converts them
* to lower case before encoding and sending to the server. The server side handler verifies
* that it receives the header names in lower case and if it doesn't then it returns a

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -21,7 +21,7 @@
* questions.
*/
/**
/*
* @test
* @bug 8306040
* @summary HttpResponseInputStream.available() returns 1 on empty stream
@ -47,19 +47,17 @@ import java.net.http.HttpResponse;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HttpInputStreamAvailableTest {
private HttpServer server;
private int port;
static final String TEST_MESSAGE = "This is test message";
static final int ZERO = 0;
private static HttpServer server;
private static int port;
private static final String TEST_MESSAGE = "This is test message";
private static final int ZERO = 0;
@BeforeAll
void setup() throws Exception {
static void setup() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress(loopback, 0);
server = HttpServer.create(addr, 0);
@ -72,69 +70,71 @@ public class HttpInputStreamAvailableTest {
}
@AfterAll
void teardown() throws Exception {
static void teardown() throws Exception {
server.stop(0);
}
@Test
public void test() throws Exception {
HttpClient client = HttpClient
try (HttpClient client = HttpClient
.newBuilder()
.proxy(HttpClient.Builder.NO_PROXY)
.build();
.build()) {
URI uri = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/NonZeroResponse/")
.build();
URI uri = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/NonZeroResponse/")
.build();
HttpRequest request = HttpRequest
.newBuilder(uri)
.GET()
.build();
HttpRequest request = HttpRequest
.newBuilder(uri)
.GET()
.build();
// Send a httpRequest and assert the bytes available
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try ( InputStream in = response.body()) {
in.readNBytes(2);
// this is not guaranteed, but a failure here would be surprising
assertEquals(TEST_MESSAGE.length() - 2, in.available());
//read the remaining data
in.readAllBytes();
//available should return 0
assertEquals(ZERO, in.available());
// Send a httpRequest and assert the bytes available
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try (InputStream in = response.body()) {
in.readNBytes(2);
// this is not guaranteed, but a failure here would be surprising
assertEquals(TEST_MESSAGE.length() - 2, in.available());
//read the remaining data
in.readAllBytes();
//available should return 0
assertEquals(ZERO, in.available());
}
}
}
@Test
public void test1() throws Exception {
HttpClient client = HttpClient
try (HttpClient client = HttpClient
.newBuilder()
.proxy(HttpClient.Builder.NO_PROXY)
.build();
.build()) {
URI uri = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/ZeroResponse/")
.build();
URI uri = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/ZeroResponse/")
.build();
HttpRequest request = HttpRequest
.newBuilder(uri)
.GET()
.build();
HttpRequest request = HttpRequest
.newBuilder(uri)
.GET()
.build();
// Send a httpRequest and assert the bytes available
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try ( InputStream in = response.body()) {
assertEquals(ZERO, in.available());
in.readAllBytes();
assertEquals(ZERO, in.available());
// Send a httpRequest and assert the bytes available
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try (InputStream in = response.body()) {
assertEquals(ZERO, in.available());
in.readAllBytes();
assertEquals(ZERO, in.available());
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,6 @@ import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.IOException;
import java.io.InputStream;
@ -53,18 +52,17 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HttpResponseInputStreamInterruptTest {
HttpServer server;
int port;
private final CountDownLatch interruptReadyLatch = new CountDownLatch(2);
private final CountDownLatch interruptDoneLatch = new CountDownLatch(1);
private static HttpServer server;
private static int port;
private static final CountDownLatch interruptReadyLatch = new CountDownLatch(2);
private static final CountDownLatch interruptDoneLatch = new CountDownLatch(1);
static final String FIRST_MESSAGE = "Should be received";
static final String SECOND_MESSAGE = "Shouldn't be received";
@BeforeAll
void before() throws Exception {
static void before() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress(loopback, 0);
server = HttpServer.create(addr, 0);
@ -75,7 +73,7 @@ public class HttpResponseInputStreamInterruptTest {
}
@AfterAll
void after() throws Exception {
static void after() throws Exception {
server.stop(0);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
* @library /test/lib /test/jdk/java/net/httpclient/lib
* @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext
* ReferenceTracker
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.HttpClient.log=requests,responses,errors
* ISO_8859_1_Test
* @summary Tests that a client is able to receive ISO-8859-1 encoded header values.
@ -48,7 +48,6 @@ import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
@ -60,21 +59,11 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import javax.net.ssl.SSLContext;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static java.net.http.HttpClient.Version.HTTP_1_1;
@ -82,30 +71,38 @@ import static java.net.http.HttpClient.Version.HTTP_2;
import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class ISO_8859_1_Test implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
DummyServer http1DummyServer;
HttpTestServer http1TestServer; // HTTP/1.1 ( http )
HttpTestServer https1TestServer; // HTTPS/1.1 ( https )
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer http3TestServer; // HTTP/3 ( h3 )
String http1Dummy;
String http1URI;
String https1URI;
String http2URI;
String https2URI;
String http3URI;
private static DummyServer http1DummyServer;
private static HttpTestServer http1TestServer; // HTTP/1.1 ( http )
private static HttpTestServer https1TestServer; // HTTPS/1.1 ( https )
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3 ( h3 )
private static String http1Dummy;
private static String http1URI;
private static String https1URI;
private static String http2URI;
private static String https2URI;
private static String http3URI;
static final int RESPONSE_CODE = 200;
static final int ITERATION_COUNT = 4;
static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
static final Class<CompletionException> CE = CompletionException.class;
// a shared executor helps reduce the amount of threads created by the test
static final Executor executor = new TestExecutor(Executors.newCachedThreadPool());
static final ConcurrentMap<String, Throwable> FAILURES = new ConcurrentHashMap<>();
@ -121,8 +118,8 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -148,40 +145,40 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
try {
var failed = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
FAILURES.putAll(failed);
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
if (FAILURES.isEmpty()) return;
@ -199,7 +196,7 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
}
}
private String[] uris() {
private static String[] uris() {
return new String[] {
http3URI,
http1Dummy,
@ -210,13 +207,7 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
};
}
static AtomicLong URICOUNT = new AtomicLong();
@DataProvider(name = "variants")
public Object[][] variants(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
return new Object[0][];
}
public static Object[][] variants() {
String[] uris = uris();
Object[][] result = new Object[uris.length * 2][];
int i = 0;
@ -265,7 +256,7 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
}
}
private static final Exception completionCause(CompletionException x) {
private static Exception completionCause(CompletionException x) {
Throwable c = x;
while (c instanceof CompletionException
|| c instanceof ExecutionException) {
@ -285,10 +276,11 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
return builder;
}
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
public void test(String uri, boolean sameClient) throws Exception {
checkSkip();
System.out.println("Request to " + uri);
System.out.printf("%n%s-- test sameClient=%s uri=%s%n%n", now(), sameClient, uri);
HttpClient client = newHttpClient(uri, sameClient);
@ -307,7 +299,7 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
var response = cf.get();
System.out.println("Got: " + response);
var value = response.headers().firstValue("Header8859").orElse(null);
assertEquals(value, "U\u00ffU");
assertEquals("U\u00ffU", value);
}
System.out.println("HttpClient: PASSED");
if (uri.contains("http1")) {
@ -317,10 +309,10 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
conn.connect();
conn.getInputStream().readAllBytes();
var value = conn.getHeaderField("Header8859");
assertEquals(value, "U\u00ffU", "legacy stack failed");
assertEquals("U\u00ffU", value, "legacy stack failed");
System.out.println("URLConnection: PASSED");
}
System.out.println("test: DONE");
System.out.println(now() + "test: DONE");
}
static final class DummyServer extends Thread implements AutoCloseable {
@ -335,8 +327,8 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
static final InetSocketAddress LOOPBACK =
new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
final ServerSocket socket;
final CopyOnWriteArrayList<Socket> accepted = new CopyOnWriteArrayList<Socket>();
final CompletableFuture<Void> done = new CompletableFuture();
final CopyOnWriteArrayList<Socket> accepted = new CopyOnWriteArrayList<>();
final CompletableFuture<Void> done = new CompletableFuture<>();
volatile boolean closed;
DummyServer() throws IOException {
socket = new ServerSocket();
@ -387,11 +379,11 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
}
}
final void close(AutoCloseable toclose) {
void close(AutoCloseable toclose) {
try { toclose.close(); } catch (Exception x) {};
}
final public void close() {
public void close() {
closed = true;
close(socket);
accepted.forEach(this::close);
@ -410,8 +402,8 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
}
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
HttpServerAdapters.HttpTestHandler handler = new ISO88591Handler();
InetSocketAddress loopback = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
@ -448,8 +440,8 @@ public class ISO_8859_1_Test implements HttpServerAdapters {
http3TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
String sharedClientName =
sharedClient == null ? null : sharedClient.toString();
sharedClient = null;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,34 +27,20 @@
* @summary checks that a different proxy returned for
* the same host:port is taken into account
* @library /test/lib /test/jdk/java/net/httpclient/lib
* @build DigestEchoServer ProxySelectorTest jdk.httpclient.test.lib.http2.Http2TestServer
* @build DigestEchoServer ProxySelectorTest
* jdk.test.lib.net.SimpleSSLContext
* @run testng/othervm
* @run junit/othervm
* -Djdk.http.auth.tunneling.disabledSchemes
* -Djdk.httpclient.HttpClient.log=headers,requests
* -Djdk.internal.httpclient.debug=true
* ProxySelectorTest
*/
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
@ -63,7 +49,6 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
@ -73,37 +58,44 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.httpclient.test.lib.http2.Http2TestServer;
import static java.lang.System.err;
import static java.lang.System.out;
import static java.net.http.HttpClient.Version.HTTP_1_1;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.testng.Assert.assertEquals;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
public class ProxySelectorTest implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer httpTestServer; // HTTP/1.1
HttpTestServer proxyHttpTestServer; // HTTP/1.1
HttpTestServer authProxyHttpTestServer; // HTTP/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
DigestEchoServer.TunnelingProxy proxy;
DigestEchoServer.TunnelingProxy authproxy;
String httpURI;
String httpsURI;
String proxyHttpURI;
String authProxyHttpURI;
String http2URI;
String https2URI;
HttpClient client;
private static HttpTestServer httpTestServer; // HTTP/1.1
private static HttpTestServer proxyHttpTestServer; // HTTP/1.1
private static HttpTestServer authProxyHttpTestServer; // HTTP/1.1
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer httpsTestServer; // HTTPS/1.1
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static DigestEchoServer.TunnelingProxy proxy;
private static DigestEchoServer.TunnelingProxy authproxy;
private static String httpURI;
private static String httpsURI;
private static String proxyHttpURI;
private static String http2URI;
private static String https2URI;
private static HttpClient client;
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
static final long SLEEP_AFTER_TEST = 0; // milliseconds
static final int ITERATIONS = 3;
static final Executor executor = new TestExecutor(Executors.newCachedThreadPool());
@ -144,34 +136,38 @@ public class ProxySelectorTest implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests() {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
try {
// Exceptions should already have been added to FAILURES
@ -204,12 +200,10 @@ public class ProxySelectorTest implements HttpServerAdapters {
static final int UNAUTHORIZED = 401;
static final int PROXY_UNAUTHORIZED = 407;
static final int HTTP_OK = 200;
static final String MESSAGE = "Unauthorized";
enum Schemes {
HTTP, HTTPS
}
@DataProvider(name = "all")
public Object[][] positive() {
public static Object[][] positive() {
return new Object[][] {
{ Schemes.HTTP, HTTP_1_1, httpURI, true},
{ Schemes.HTTP, HttpClient.Version.HTTP_2, http2URI, true},
@ -222,15 +216,13 @@ public class ProxySelectorTest implements HttpServerAdapters {
};
}
static final AtomicLong requestCounter = new AtomicLong();
static final AtomicLong sleepCount = new AtomicLong();
@Test(dataProvider = "all")
@ParameterizedTest
@MethodSource("positive")
void test(Schemes scheme, HttpClient.Version version, String uri, boolean async)
throws Throwable
{
checkSkip();
var name = String.format("test(%s, %s, %s)", scheme, version, async);
out.printf("%n---- starting %s ----%n", name);
@ -260,7 +252,7 @@ public class ProxySelectorTest implements HttpServerAdapters {
HttpRequest request = requestBuilder.build();
out.println("Sending request: " + request.uri());
HttpResponse<T> response = null;
HttpResponse<T> response;
if (async) {
response = client.send(request, handler);
} else {
@ -288,9 +280,11 @@ public class ProxySelectorTest implements HttpServerAdapters {
// A plain server or https server should serve it, and we should get 200 OK
response = send(client, uri1, BodyHandlers.ofString(), async);
out.println("Got response from plain server: " + response);
assertEquals(response.statusCode(), HTTP_OK);
assertEquals(response.headers().firstValue("X-value"),
scheme == Schemes.HTTPS ? Optional.of("https-server") : Optional.of("plain-server"));
assertEquals(HTTP_OK, response.statusCode());
assertEquals(scheme == Schemes.HTTPS
? Optional.of("https-server")
: Optional.of("plain-server"),
response.headers().firstValue("X-value"));
// Second request should go through a non authenticating proxy.
// For a clear connection - a proxy-server should serve it, and we should get 200 OK
@ -298,9 +292,11 @@ public class ProxySelectorTest implements HttpServerAdapters {
// authenticating proxy - and we should receive 200 OK from an https-server
response = send(client, uri2, BodyHandlers.ofString(), async);
out.println("Got response through noauth proxy: " + response);
assertEquals(response.statusCode(), HTTP_OK);
assertEquals(response.headers().firstValue("X-value"),
scheme == Schemes.HTTPS ? Optional.of("https-server") : Optional.of("proxy-server"));
assertEquals(HTTP_OK, response.statusCode());
assertEquals(scheme == Schemes.HTTPS
? Optional.of("https-server")
: Optional.of("proxy-server"),
response.headers().firstValue("X-value"));
// Third request should go through an authenticating proxy.
// For a clear connection - an auth-proxy-server should serve it, and we
@ -310,16 +306,18 @@ public class ProxySelectorTest implements HttpServerAdapters {
// proxy - so the X-value header will be absent
response = send(client, uri3, BodyHandlers.ofString(), async);
out.println("Got response through auth proxy: " + response);
assertEquals(response.statusCode(), PROXY_UNAUTHORIZED);
assertEquals(response.headers().firstValue("X-value"),
scheme == Schemes.HTTPS ? Optional.empty() : Optional.of("auth-proxy-server"));
assertEquals(PROXY_UNAUTHORIZED, response.statusCode());
assertEquals(scheme == Schemes.HTTPS
? Optional.empty()
: Optional.of("auth-proxy-server"),
response.headers().firstValue("X-value"));
}
// -- Infrastructure
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
httpTestServer = HttpTestServer.create(HTTP_1_1);
httpTestServer.addHandler(new PlainServerHandler("plain-server"), "/http1/");
httpURI = "http://" + httpTestServer.serverAuthority() + "/http1";
@ -368,8 +366,8 @@ public class ProxySelectorTest implements HttpServerAdapters {
serverCount.incrementAndGet();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
client = null;
Thread.sleep(100);
AssertionError fail = TRACKER.check(1500);
@ -387,7 +385,7 @@ public class ProxySelectorTest implements HttpServerAdapters {
}
}
class TestProxySelector extends ProxySelector {
static final class TestProxySelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
String path = uri.getPath();
@ -426,11 +424,8 @@ public class ProxySelectorTest implements HttpServerAdapters {
String path = t.getRequestURI().getPath();
HttpTestRequestHeaders reqh = t.getRequestHeaders();
HttpTestResponseHeaders rsph = t.getResponseHeaders();
String xValue = serverType;
rsph.addHeader("X-value", serverType);
t.getResponseHeaders().addHeader("X-value", xValue);
byte[] body = "RESPONSE".getBytes(UTF_8);
t.sendResponseHeaders(HTTP_OK, body.length);
try (var out = t.getResponseBody()) {
@ -449,20 +444,16 @@ public class ProxySelectorTest implements HttpServerAdapters {
@Override
public void handle(HttpTestExchange t) throws IOException {
readAllRequestData(t); // shouldn't be any
String method = t.getRequestMethod();
String path = t.getRequestURI().getPath();
HttpTestRequestHeaders reqh = t.getRequestHeaders();
HttpTestResponseHeaders rsph = t.getResponseHeaders();
String xValue = serverType;
String srv = path.contains("/proxy/") ? "proxy" : "server";
String prefix = path.contains("/proxy/") ? "Proxy-" : "WWW-";
int code = path.contains("/proxy/") ? PROXY_UNAUTHORIZED : UNAUTHORIZED;
String resp = prefix + "Unauthorized";
rsph.addHeader(prefix + "Authenticate", "Basic realm=\"earth\", charset=\"UTF-8\"");
byte[] body = resp.getBytes(UTF_8);
t.getResponseHeaders().addHeader("X-value", xValue);
rsph.addHeader("X-value", serverType);
t.sendResponseHeaders(code, body.length);
try (var out = t.getResponseBody()) {
out.write(body);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
* @library /test/lib /test/jdk/java/net/httpclient/lib
* @build jdk.test.lib.net.SimpleSSLContext
* ReferenceTracker jdk.httpclient.test.lib.common.HttpServerAdapters
* @run testng/othervm -Djdk.internal.httpclient.debug=true
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.HttpClient.log=requests,responses,errors
* Response204V2Test
* @summary Tests that streams are closed after receiving a 204 response.
@ -44,7 +44,6 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -52,19 +51,9 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
@ -74,15 +63,25 @@ import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static java.net.http.HttpOption.H3_DISCOVERY;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class Response204V2Test implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer http3TestServer; // HTTP/3 ( h3 )
String http2URI;
String https2URI;
String http3URI;
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3 ( h3 )
private static String http2URI;
private static String https2URI;
private static String http3URI;
static final int RESPONSE_CODE = 204;
static final int ITERATION_COUNT = 4;
@ -101,8 +100,8 @@ public class Response204V2Test implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -128,40 +127,40 @@ public class Response204V2Test implements HttpServerAdapters {
}
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static final void printFailedTests() {
out.println("\n=========================");
try {
var failed = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
FAILURES.putAll(failed);
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
if (FAILURES.isEmpty()) return;
@ -179,7 +178,7 @@ public class Response204V2Test implements HttpServerAdapters {
}
}
private String[] uris() {
private static String[] uris() {
return new String[] {
http3URI,
http2URI,
@ -187,13 +186,7 @@ public class Response204V2Test implements HttpServerAdapters {
};
}
static AtomicLong URICOUNT = new AtomicLong();
@DataProvider(name = "variants")
public Object[][] variants(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
return new Object[0][];
}
public static Object[][] variants() {
String[] uris = uris();
Object[][] result = new Object[uris.length * 2][];
int i = 0;
@ -232,23 +225,6 @@ public class Response204V2Test implements HttpServerAdapters {
}
}
static void checkStatus(int expected, int found) throws Exception {
if (expected != found) {
System.err.printf ("Test failed: wrong status code %d/%d\n",
expected, found);
throw new RuntimeException("Test failed");
}
}
static void checkStrings(String expected, String found) throws Exception {
if (!expected.equals(found)) {
System.err.printf ("Test failed: wrong string %s/%s\n",
expected, found);
throw new RuntimeException("Test failed");
}
}
private HttpRequest.Builder newRequestBuilder(URI uri) {
var builder = HttpRequest.newBuilder(uri);
if (uri.getRawPath().contains("/http3/")) {
@ -258,10 +234,10 @@ public class Response204V2Test implements HttpServerAdapters {
return builder;
}
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
public void test(String uri, boolean sameClient) throws Exception {
checkSkip();
out.println("Request to " + uri);
out.printf("%n%s-- test sameClient=%s, uri=%s%n%n", now(), sameClient, uri);
HttpClient client = newHttpClient(uri, sameClient);
@ -282,8 +258,8 @@ public class Response204V2Test implements HttpServerAdapters {
out.println("test: DONE");
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
// HTTP/2
HttpTestHandler handler204 = new Handler204();
@ -305,8 +281,8 @@ public class Response204V2Test implements HttpServerAdapters {
http3TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
String sharedClientName =
sharedClient == null ? null : sharedClient.toString();
sharedClient = null;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,24 +36,16 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLServerSocketFactory;
@ -64,28 +56,40 @@ import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpResponse.BodyHandlers.ofString;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.stream.Collectors.toList;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public abstract class ShortResponseBody {
Server closeImmediatelyServer;
Server closeImmediatelyHttpsServer;
Server variableLengthServer;
Server variableLengthHttpsServer;
Server fixedLengthServer;
private static Server closeImmediatelyServer;
private static Server closeImmediatelyHttpsServer;
private static Server variableLengthServer;
private static Server variableLengthHttpsServer;
private static Server fixedLengthServer;
String httpURIClsImed;
String httpsURIClsImed;
String httpURIVarLen;
String httpsURIVarLen;
String httpURIFixLen;
private static String httpURIClsImed;
private static String httpsURIClsImed;
private static String httpURIVarLen;
private static String httpsURIVarLen;
private static String httpURIFixLen;
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
SSLParameters sslParameters;
HttpClient client;
int numberOfRequests;
private static SSLParameters sslParameters;
protected static HttpClient client;
private static int numberOfRequests;
static final int REQUESTS_PER_CLIENT = 10; // create new client every 10 requests
static final long PAUSE_FOR_GC = 5; // 5ms to let gc work
@ -99,7 +103,7 @@ public abstract class ShortResponseBody {
static final AtomicLong reqnb = new AtomicLong();
static final AtomicLong ids = new AtomicLong();
final ThreadFactory factory = new ThreadFactory() {
private static final ThreadFactory factory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "HttpClient-Worker-" + ids.incrementAndGet());
@ -107,21 +111,49 @@ public abstract class ShortResponseBody {
return thread;
}
};
final ExecutorService service = Executors.newCachedThreadPool(factory);
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
private static final ExecutorService service = Executors.newCachedThreadPool(factory);
static final ConcurrentMap<String, Throwable> FAILURES = new ConcurrentHashMap<>();
static final long start = System.nanoTime();
public static String now() {
long now = System.nanoTime() - start;
long secs = now / 1000_000_000;
long mill = (now % 1000_000_000) / 1000_000;
long nan = now % 1000_000;
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
@BeforeMethod
void beforeMethod(ITestContext context) {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@BeforeEach
void beforeMethod() {
if (client == null || numberOfRequests == REQUESTS_PER_CLIENT) {
numberOfRequests = 0;
out.println("--- new client");
@ -134,22 +166,12 @@ public abstract class ShortResponseBody {
}
}
numberOfRequests++;
if (context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
}
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@AfterAll
static void printFailedTests() {
out.println("\n=========================\n");
try {
var FAILURES = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
if (FAILURES.isEmpty()) return;
out.println("Failed tests: ");
FAILURES.entrySet().forEach((e) -> {
@ -162,8 +184,7 @@ public abstract class ShortResponseBody {
}
}
@DataProvider(name = "sanity")
public Object[][] sanity() {
public static Object[][] sanity() {
return new Object[][]{
{ httpURIVarLen + "?length=all" },
{ httpsURIVarLen + "?length=all" },
@ -175,22 +196,22 @@ public abstract class ShortResponseBody {
return url.replace("%reqnb%", String.valueOf(reqnb.incrementAndGet()));
}
@Test(dataProvider = "sanity")
@ParameterizedTest
@MethodSource("sanity")
void sanity(String url) throws Exception {
url = uniqueURL(url);
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build();
out.println("Request: " + request);
HttpResponse<String> response = client.send(request, ofString());
String body = response.body();
assertEquals(body, EXPECTED_RESPONSE_BODY);
assertEquals(EXPECTED_RESPONSE_BODY, body);
client.sendAsync(request, ofString())
.thenApply(resp -> resp.body())
.thenAccept(b -> assertEquals(b, EXPECTED_RESPONSE_BODY))
.thenAccept(b -> assertEquals(EXPECTED_RESPONSE_BODY, b))
.join();
}
@DataProvider(name = "sanityBadRequest")
public Object[][] sanityBadRequest() {
public static Object[][] sanityBadRequest() {
return new Object[][]{
{ httpURIVarLen }, // no query string
{ httpsURIVarLen },
@ -198,18 +219,18 @@ public abstract class ShortResponseBody {
};
}
@Test(dataProvider = "sanityBadRequest")
@ParameterizedTest
@MethodSource("sanityBadRequest")
void sanityBadRequest(String url) throws Exception {
url = uniqueURL(url);
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build();
out.println("Request: " + request);
HttpResponse<String> response = client.send(request, ofString());
assertEquals(response.statusCode(), 400);
assertEquals(response.body(), "");
assertEquals(400, response.statusCode());
assertEquals("", response.body());
}
@DataProvider(name = "uris")
public Object[][] variants(ITestContext context) {
public static Object[][] variants() {
String[][] cases = new String[][] {
// The length query string is the total number of bytes in the reply,
// including headers, before the server closes the connection. The
@ -268,13 +289,6 @@ public abstract class ShortResponseBody {
{ httpsURIClsImed, "no bytes"},
};
if (context.getFailedTests().size() > 0) {
// Shorten the log output by preventing useless
// skip traces to be printed for subsequent methods
// if one of the previous @Test method has failed.
return new Object[0][];
}
return cases;
}
@ -618,7 +632,7 @@ public abstract class ShortResponseBody {
String response( ) { return RESPONSE; }
}
/** A server that issues a, possibly-partial, chunked reply over SSL. */
/** A server that issues a possibly-partial, chunked reply over SSL. */
static final class SSLVariableLengthServer extends PlainVariableLengthServer {
SSLVariableLengthServer() throws IOException {
super("SSLVariableLengthServer");
@ -655,8 +669,8 @@ public abstract class ShortResponseBody {
+ server.getPort();
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
SSLContext.setDefault(sslContext);
sslParameters = new SSLParameters();
@ -682,8 +696,8 @@ public abstract class ShortResponseBody {
+ "/http1/fixed/req=%reqnb%/baz";
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
closeImmediatelyServer.close();
closeImmediatelyHttpsServer.close();
variableLengthServer.close();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,7 @@
* received before a socket exception or eof.
* @library /test/lib
* @build jdk.test.lib.net.SimpleSSLContext ShortResponseBody ShortResponseBodyGet
* @run testng/othervm
* @run junit/othervm
* -Djdk.httpclient.HttpClient.log=headers,errors,channel
* ShortResponseBodyGet
*/
@ -38,21 +38,24 @@ import java.net.URI;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.ExecutionException;
import org.testng.annotations.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static java.lang.System.out;
import static java.net.http.HttpResponse.BodyHandlers.ofString;
import static org.testng.Assert.fail;
import static org.junit.jupiter.api.Assertions.fail;
public class ShortResponseBodyGet extends ShortResponseBody {
@Test(dataProvider = "uris")
@ParameterizedTest
@MethodSource("variants")
void testSynchronousGET(String urlp, String expectedMsg)
throws Exception
{
checkSkip();
String url = uniqueURL(urlp);
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build();
out.println("Request: " + request);
out.printf("%n%s-- testSynchronousGET Request: %s%n%n", now(), request);
try {
HttpResponse<String> response = client.send(request, ofString());
String body = response.body();
@ -67,14 +70,14 @@ public class ShortResponseBodyGet extends ShortResponseBody {
}
}
@Test(dataProvider = "uris")
@ParameterizedTest
@MethodSource("variants")
void testAsynchronousGET(String urlp, String expectedMsg)
throws Exception
{
checkSkip();
String url = uniqueURL(urlp);
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build();
out.println("Request: " + request);
out.printf("%n%s-- testAsynchronousGET Request: %s%n%n", now(), request);
try {
HttpResponse<String> response = client.sendAsync(request, ofString()).get();
String body = response.body();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,7 @@
* received before a socket exception or eof.
* @library /test/lib
* @build jdk.test.lib.net.SimpleSSLContext ShortResponseBody ShortResponseBodyPost
* @run testng/othervm
* @run junit/othervm
* -Djdk.httpclient.HttpClient.log=headers,errors,channel
* -Djdk.internal.httpclient.debug=true
* ShortResponseBodyPost
@ -42,10 +42,14 @@ import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.testng.annotations.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static java.lang.System.out;
import static java.net.http.HttpResponse.BodyHandlers.ofString;
import static org.testng.Assert.fail;
import static org.junit.jupiter.api.Assertions.fail;
public class ShortResponseBodyPost extends ShortResponseBody {
// POST tests are racy in what may be received before writing may cause a
@ -56,16 +60,16 @@ public class ShortResponseBodyPost extends ShortResponseBody {
List.of("no bytes", "status line", "header");
@Test(dataProvider = "uris")
@ParameterizedTest
@MethodSource("variants")
void testSynchronousPOST(String urlp, String expectedMsg)
throws Exception
{
checkSkip();
String url = uniqueURL(urlp);
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.POST(BodyPublishers.ofInputStream(() -> new InfiniteInputStream()))
.build();
out.println("Request: " + request);
out.printf("%n%s-- testSynchronousPOST Request: %s%n%n", now(), request);
try {
HttpResponse<String> response = client.send(request, ofString());
String body = response.body();
@ -86,16 +90,16 @@ public class ShortResponseBodyPost extends ShortResponseBody {
}
}
@Test(dataProvider = "uris")
@ParameterizedTest
@MethodSource("variants")
void testAsynchronousPOST(String urlp, String expectedMsg)
throws Exception
{
checkSkip();
String url = uniqueURL(urlp);
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.POST(BodyPublishers.ofInputStream(() -> new InfiniteInputStream()))
.build();
out.println("Request: " + request);
out.printf("%n%s-- testAsynchronousPOST Request: %s%n%n", now(), request);
try {
HttpResponse<String> response = client.sendAsync(request, ofString()).get();
String body = response.body();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
* @library /test/lib
* @build jdk.test.lib.net.SimpleSSLContext
* @build ShortResponseBody ShortResponseBodyPost
* @run testng/othervm
* @run junit/othervm
* -Djdk.httpclient.HttpClient.log=headers,errors,channel
* -Djdk.httpclient.enableAllMethodRetry
* -Djdk.internal.httpclient.debug=true

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,35 +31,22 @@
* jdk.httpclient.test.lib.http2.Http2TestServer
* jdk.test.lib.net.SimpleSSLContext
* @requires (vm.compMode != "Xcomp")
* @run testng/othervm/timeout=480
* @run junit/othervm/timeout=480
* -Djdk.httpclient.HttpClient.log=requests,headers,errors
* SpecialHeadersTest
* @run testng/othervm/timeout=480 -Djdk.httpclient.allowRestrictedHeaders=Host
* @run junit/othervm/timeout=480 -Djdk.httpclient.allowRestrictedHeaders=Host
* -Djdk.httpclient.HttpClient.log=requests,headers,errors
* SpecialHeadersTest
*/
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import jdk.internal.net.http.common.OperationTrackers.Tracker;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
@ -83,9 +70,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.httpclient.test.lib.http2.Http2TestServer;
import static java.lang.System.err;
import static java.lang.System.out;
@ -93,22 +78,37 @@ import static java.net.http.HttpClient.Builder.NO_PROXY;
import static java.net.http.HttpClient.Version.HTTP_1_1;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.net.http.HttpClient.Version.HTTP_3;
import static java.net.http.HttpOption.H3_DISCOVERY;
import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
import static java.nio.charset.StandardCharsets.US_ASCII;
import org.testng.Assert;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class SpecialHeadersTest implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
String httpURI;
String httpsURI;
String http2URI;
String https2URI;
private static HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
private static HttpTestServer httpsTestServer; // HTTPS/1.1
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3
private static String httpURI;
private static String httpsURI;
private static String http2URI;
private static String https2URI;
private static String https3URI;
static final String[][] headerNamesAndValues = new String[][]{
{"User-Agent: <DEFAULT>"},
@ -132,8 +132,7 @@ public class SpecialHeadersTest implements HttpServerAdapters {
{"hoSt: mixed"}
};
@DataProvider(name = "variants")
public Object[][] variants() {
public static Object[][] variants() {
String prop = System.getProperty("jdk.httpclient.allowRestrictedHeaders");
boolean hostTest = prop != null && prop.equalsIgnoreCase("host");
final String[][] testInput = hostTest ? headerNamesAndValues1 : headerNamesAndValues;
@ -153,6 +152,9 @@ public class SpecialHeadersTest implements HttpServerAdapters {
Arrays.asList(testInput).stream()
.map(e -> new Object[] {https2URI, e[0], sameClient})
.forEach(list::add);
Arrays.asList(testInput).stream()
.map(e -> new Object[] {https3URI, e[0], sameClient})
.forEach(list::add);
}
return list.stream().toArray(Object[][]::new);
}
@ -173,8 +175,8 @@ public class SpecialHeadersTest implements HttpServerAdapters {
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private volatile HttpClient sharedClient;
private static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
private static volatile HttpClient sharedClient;
static class TestExecutor implements Executor {
final AtomicLong tasks = new AtomicLong();
@ -209,38 +211,39 @@ public class SpecialHeadersTest implements HttpServerAdapters {
}
protected boolean stopAfterFirstFailure() {
private static boolean stopAfterFirstFailure() {
return Boolean.getBoolean("jdk.internal.httpclient.debug");
}
final AtomicReference<SkipException> skiptests = new AtomicReference<>();
void checkSkip() {
var skip = skiptests.get();
if (skip != null) throw skip;
}
static String name(ITestResult result) {
var params = result.getParameters();
return result.getName()
+ (params == null ? "()" : Arrays.toString(result.getParameters()));
}
@BeforeMethod
void beforeMethod(ITestContext context) {
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
if (skiptests.get() == null) {
SkipException skip = new SkipException("some tests failed");
skip.setStackTrace(new StackTraceElement[0]);
skiptests.compareAndSet(null, skip);
static final class TestStopper implements TestWatcher, BeforeEachCallback {
final AtomicReference<String> failed = new AtomicReference<>();
TestStopper() { }
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
if (stopAfterFirstFailure()) {
String msg = "Aborting due to: " + cause;
failed.compareAndSet(null, msg);
FAILURES.putIfAbsent(context.getDisplayName(), cause);
System.out.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
System.err.printf("%nTEST FAILED: %s%s%n\tAborting due to %s%n%n",
now(), context.getDisplayName(), cause);
}
}
@Override
public void beforeEach(ExtensionContext context) {
String msg = failed.get();
Assumptions.assumeTrue(msg == null, msg);
}
}
@AfterClass
static final void printFailedTests(ITestContext context) {
@RegisterExtension
static final TestStopper stopper = new TestStopper();
@AfterAll
static void printFailedTests() {
out.println("\n=========================");
var failed = context.getFailedTests().getAllResults().stream()
.collect(Collectors.toMap(r -> name(r), ITestResult::getThrowable));
FAILURES.putAll(failed);
try {
out.printf("%n%sCreated %d servers and %d clients%n",
now(), serverCount.get(), clientCount.get());
@ -260,7 +263,7 @@ public class SpecialHeadersTest implements HttpServerAdapters {
private HttpClient makeNewClient() {
clientCount.incrementAndGet();
return HttpClient.newBuilder()
return newClientBuilderForH3()
.proxy(NO_PROXY)
.executor(executor)
.sslContext(sslContext)
@ -307,7 +310,8 @@ public class SpecialHeadersTest implements HttpServerAdapters {
if (throwable instanceof Error e) throw e;
}
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
void test(String uriString,
String headerNameAndValue,
boolean sameClient)
@ -335,6 +339,10 @@ public class SpecialHeadersTest implements HttpServerAdapters {
}
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri);
if (uriString.contains("/http3")) {
requestBuilder.version(HTTP_3);
requestBuilder.setOption(H3_DISCOVERY, HTTP_3_URI_ONLY);
}
if (!useDefault) {
requestBuilder.header(name, value);
}
@ -343,7 +351,7 @@ public class SpecialHeadersTest implements HttpServerAdapters {
out.println("Got response: " + resp);
out.println("Got body: " + resp.body());
assertEquals(resp.statusCode(), 200,
assertEquals(200, resp.statusCode(),
"Expected 200, got:" + resp.statusCode());
boolean isInitialRequest = i == 0;
@ -366,10 +374,10 @@ public class SpecialHeadersTest implements HttpServerAdapters {
: resp.headers().firstValue("X-" + key).get();
out.println("Got X-" + key + ": " + resp.headers().allValues("X-" + key));
if (value != null) {
assertEquals(receivedHeaderString, value);
assertEquals(resp.headers().allValues("X-" + key), List.of(value));
assertEquals(value, receivedHeaderString);
assertEquals(List.of(value), resp.headers().allValues("X-" + key));
} else {
assertEquals(resp.headers().allValues("X-" + key).size(), 0);
assertEquals(0, resp.headers().allValues("X-" + key).size());
}
}
} catch (Throwable x) {
@ -389,7 +397,8 @@ public class SpecialHeadersTest implements HttpServerAdapters {
}
}
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
void testHomeMadeIllegalHeader(String uriString,
String headerNameAndValue,
boolean sameClient)
@ -443,7 +452,7 @@ public class SpecialHeadersTest implements HttpServerAdapters {
try {
HttpResponse<String> response = client.send(req, BodyHandlers.ofString());
Assert.fail("Unexpected reply: " + response);
Assertions.fail("Unexpected reply: " + response);
} catch (IllegalArgumentException ee) {
out.println("Got IAE as expected");
}
@ -465,7 +474,8 @@ public class SpecialHeadersTest implements HttpServerAdapters {
@Test(dataProvider = "variants")
@ParameterizedTest
@MethodSource("variants")
void testAsync(String uriString, String headerNameAndValue, boolean sameClient)
throws Exception
{
@ -490,6 +500,10 @@ public class SpecialHeadersTest implements HttpServerAdapters {
}
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri);
if (uriString.contains("/http3")) {
requestBuilder.version(HTTP_3);
requestBuilder.setOption(H3_DISCOVERY, HTTP_3_URI_ONLY);
}
if (!useDefault) {
requestBuilder.header(name, value);
}
@ -504,7 +518,7 @@ public class SpecialHeadersTest implements HttpServerAdapters {
.thenApply(response -> {
out.println("Got response: " + response);
out.println("Got body: " + response.body());
assertEquals(response.statusCode(), 200);
assertEquals(200, response.statusCode());
return response;
})
.thenAccept(resp -> {
@ -522,10 +536,10 @@ public class SpecialHeadersTest implements HttpServerAdapters {
: resp.headers().firstValue("X-" + key).orElse(null);
out.println("Got X-" + key + ": " + resp.headers().allValues("X-" + key));
if (value != null) {
assertEquals(receivedHeaderString, value);
assertEquals(resp.headers().allValues("X-" + key), List.of(value));
assertEquals(value, receivedHeaderString);
assertEquals(List.of(value), resp.headers().allValues("X-" + key));
} else {
assertEquals(resp.headers().allValues("X-" + key).size(), 1);
assertEquals(1, resp.headers().allValues("X-" + key).size());
}
}
})
@ -552,8 +566,8 @@ public class SpecialHeadersTest implements HttpServerAdapters {
+ server.getAddress().getPort();
}
@BeforeTest
public void setup() throws Exception {
@BeforeAll
public static void setup() throws Exception {
out.println("--- Starting setup " + now());
HttpTestHandler handler = new HttpUriStringHandler();
@ -573,14 +587,19 @@ public class SpecialHeadersTest implements HttpServerAdapters {
https2TestServer.addHandler(handler, "/https2");
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2";
http3TestServer = HttpTestServer.create(HTTP_3_URI_ONLY, sslContext);
http3TestServer.addHandler(handler, "/http3");
https3URI = "https://" + http3TestServer.serverAuthority() + "/http3";
httpTestServer.start();
httpsTestServer.start();
http2TestServer.start();
https2TestServer.start();
http3TestServer.start();
}
@AfterTest
public void teardown() throws Exception {
@AfterAll
public static void teardown() throws Exception {
out.println("\n--- Teardown " + now());
HttpClient shared = sharedClient;
String sharedClientName =
@ -595,6 +614,7 @@ public class SpecialHeadersTest implements HttpServerAdapters {
httpsTestServer.stop();
http2TestServer.stop();
https2TestServer.stop();
http3TestServer.start();
executor.shutdown();
} finally {
if (fail != null) {

View File

@ -72,20 +72,19 @@ import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class StreamingBody implements HttpServerAdapters {
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer http3TestServer; // HTTP/3 ( h3 )
String httpURI;
String httpsURI;
String http2URI;
String https2URI;
String http3URI;
private static HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
private static HttpTestServer httpsTestServer; // HTTPS/1.1
private static HttpTestServer http2TestServer; // HTTP/2 ( h2c )
private static HttpTestServer https2TestServer; // HTTP/2 ( h2 )
private static HttpTestServer http3TestServer; // HTTP/3 ( h3 )
private static String httpURI;
private static String httpsURI;
private static String http2URI;
private static String https2URI;
private static String http3URI;
static final AtomicLong clientCount = new AtomicLong();
static final AtomicLong serverCount = new AtomicLong();
@ -186,7 +185,7 @@ public class StreamingBody implements HttpServerAdapters {
static final String MESSAGE = "StreamingBody message body";
static final int ITERATIONS = 100;
public Object[][] positive() {
public static Object[][] positive() {
return new Object[][] {
{ http3URI, },
{ httpURI, },
@ -253,7 +252,7 @@ public class StreamingBody implements HttpServerAdapters {
// -- Infrastructure
@BeforeAll
public void setup() throws Exception {
public static void setup() throws Exception {
httpTestServer = HttpTestServer.create(HTTP_1_1);
httpTestServer.addHandler(new MessageHandler(), "/http1/streamingbody/");
httpURI = "http://" + httpTestServer.serverAuthority() + "/http1/streamingbody/w";
@ -290,7 +289,7 @@ public class StreamingBody implements HttpServerAdapters {
}
@AfterAll
public void teardown() throws Exception {
public static void teardown() throws Exception {
try {
httpTestServer.stop();
httpsTestServer.stop();
@ -303,7 +302,7 @@ public class StreamingBody implements HttpServerAdapters {
}
}
static final void printFailedTests() {
static void printFailedTests() {
out.println("\n=========================");
try {
out.printf("%n%sCreated %s servers and %s clients%n",