8233403: Improve verbosity of some httpclient tests
Improve the verbosity of some httpclient tests to help diagnosis of intermittent failures. Also fixes ShortRequestBody test. Reviewed-by: chegar
This commit is contained in:
parent
24bff84cb3
commit
eaba9fe23b
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -25,8 +25,10 @@ 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.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;
|
||||
@ -132,6 +134,17 @@ public abstract class AbstractThrowingPublishers implements HttpServerAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean stopAfterFirstFailure() {
|
||||
return Boolean.getBoolean("jdk.internal.httpclient.debug");
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
void beforeMethod(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
throw new RuntimeException("some tests failed");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
static final void printFailedTests() {
|
||||
out.println("\n=========================");
|
||||
@ -217,7 +230,10 @@ public abstract class AbstractThrowingPublishers implements HttpServerAdapters {
|
||||
}
|
||||
|
||||
@DataProvider(name = "subscribeProvider")
|
||||
public Object[][] subscribeProvider() {
|
||||
public Object[][] subscribeProvider(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedCustomExceptionThrower(),
|
||||
new UncheckedIOExceptionThrower()),
|
||||
@ -225,7 +241,10 @@ public abstract class AbstractThrowingPublishers implements HttpServerAdapters {
|
||||
}
|
||||
|
||||
@DataProvider(name = "requestProvider")
|
||||
public Object[][] requestProvider() {
|
||||
public Object[][] requestProvider(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedCustomExceptionThrower(),
|
||||
new UncheckedIOExceptionThrower()),
|
||||
@ -233,7 +252,10 @@ public abstract class AbstractThrowingPublishers implements HttpServerAdapters {
|
||||
}
|
||||
|
||||
@DataProvider(name = "nextRequestProvider")
|
||||
public Object[][] nextRequestProvider() {
|
||||
public Object[][] nextRequestProvider(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedCustomExceptionThrower(),
|
||||
new UncheckedIOExceptionThrower()),
|
||||
@ -241,28 +263,40 @@ public abstract class AbstractThrowingPublishers implements HttpServerAdapters {
|
||||
}
|
||||
|
||||
@DataProvider(name = "beforeCancelProviderIO")
|
||||
public Object[][] beforeCancelProviderIO() {
|
||||
public Object[][] beforeCancelProviderIO(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedIOExceptionThrower()),
|
||||
EnumSet.of(Where.BEFORE_CANCEL));
|
||||
}
|
||||
|
||||
@DataProvider(name = "afterCancelProviderIO")
|
||||
public Object[][] afterCancelProviderIO() {
|
||||
public Object[][] afterCancelProviderIO(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedIOExceptionThrower()),
|
||||
EnumSet.of(Where.AFTER_CANCEL));
|
||||
}
|
||||
|
||||
@DataProvider(name = "beforeCancelProviderCustom")
|
||||
public Object[][] beforeCancelProviderCustom() {
|
||||
public Object[][] beforeCancelProviderCustom(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedCustomExceptionThrower()),
|
||||
EnumSet.of(Where.BEFORE_CANCEL));
|
||||
}
|
||||
|
||||
@DataProvider(name = "afterCancelProviderCustom")
|
||||
public Object[][] afterCancelProvider() {
|
||||
public Object[][] afterCancelProvider(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedCustomExceptionThrower()),
|
||||
EnumSet.of(Where.AFTER_CANCEL));
|
||||
|
@ -42,11 +42,12 @@
|
||||
*/
|
||||
|
||||
import jdk.test.lib.net.SimpleSSLContext;
|
||||
import org.testng.ITestContext;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.AfterClass;
|
||||
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.BufferedReader;
|
||||
@ -146,6 +147,17 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean stopAfterFirstFailure() {
|
||||
return Boolean.getBoolean("jdk.internal.httpclient.debug");
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
void beforeMethod(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
throw new RuntimeException("some tests failed");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
static final void printFailedTests() {
|
||||
out.println("\n=========================");
|
||||
@ -208,27 +220,38 @@ public abstract class AbstractThrowingPushPromises implements HttpServerAdapters
|
||||
|
||||
private Object[][] variants(List<Thrower> throwers) {
|
||||
String[] uris = uris();
|
||||
Object[][] result = new Object[uris.length * 2 * throwers.size()][];
|
||||
// reduce traces by always using the same client if
|
||||
// stopAfterFirstFailure is requested.
|
||||
List<Boolean> sameClients = stopAfterFirstFailure()
|
||||
? List.of(true)
|
||||
: List.of(false, true);
|
||||
Object[][] result = new Object[uris.length * sameClients.size() * throwers.size()][];
|
||||
int i = 0;
|
||||
for (Thrower thrower : throwers) {
|
||||
for (boolean sameClient : List.of(false, true)) {
|
||||
for (boolean sameClient : sameClients) {
|
||||
for (String uri : uris()) {
|
||||
result[i++] = new Object[]{uri, sameClient, thrower};
|
||||
}
|
||||
}
|
||||
}
|
||||
assert i == uris.length * 2 * throwers.size();
|
||||
assert i == uris.length * sameClients.size() * throwers.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
@DataProvider(name = "ioVariants")
|
||||
public Object[][] ioVariants() {
|
||||
public Object[][] ioVariants(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedIOExceptionThrower()));
|
||||
}
|
||||
|
||||
@DataProvider(name = "customVariants")
|
||||
public Object[][] customVariants() {
|
||||
public Object[][] customVariants(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
return variants(List.of(
|
||||
new UncheckedCustomExceptionThrower()));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -25,8 +25,10 @@ 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.annotations.AfterTest;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
@ -131,6 +133,17 @@ public abstract class AbstractThrowingSubscribers implements HttpServerAdapters
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean stopAfterFirstFailure() {
|
||||
return Boolean.getBoolean("jdk.internal.httpclient.debug");
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
void beforeMethod(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
throw new RuntimeException("some tests failed");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
static final void printFailedTests() {
|
||||
out.println("\n=========================");
|
||||
@ -182,7 +195,10 @@ public abstract class AbstractThrowingSubscribers implements HttpServerAdapters
|
||||
}
|
||||
|
||||
@DataProvider(name = "variants")
|
||||
public Object[][] variants() {
|
||||
public Object[][] variants(ITestContext context) {
|
||||
if (stopAfterFirstFailure() && context.getFailedTests().size() > 0) {
|
||||
return new Object[0][];
|
||||
}
|
||||
String[] uris = uris();
|
||||
Object[][] result = new Object[uris.length * 2 * 2][];
|
||||
int i = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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,6 +29,7 @@ import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
@ -76,6 +77,7 @@ public class ShortRequestBody {
|
||||
BYTE_ARRAY_BODY.length,
|
||||
fileSize(FILE_BODY) };
|
||||
static final int[] BODY_OFFSETS = new int[] { 0, +1, -1, +2, -2, +3, -3 };
|
||||
static final String MARKER = "ShortRequestBody";
|
||||
|
||||
// A delegating Body Publisher. Subtypes will have a concrete body type.
|
||||
static abstract class AbstractDelegateRequestBody
|
||||
@ -134,7 +136,7 @@ public class ShortRequestBody {
|
||||
try (Server server = new Server()) {
|
||||
for (Supplier<HttpClient> cs : clientSuppliers) {
|
||||
err.println("\n---- next supplier ----\n");
|
||||
URI uri = new URI("http://localhost:" + server.getPort() + "/");
|
||||
URI uri = new URI("http://localhost:" + server.getPort() + "/" + MARKER);
|
||||
|
||||
// sanity ( 6 requests to keep client and server offsets easy to workout )
|
||||
success(cs, uri, new StringRequestBody(STRING_BODY, 0));
|
||||
@ -248,44 +250,56 @@ public class ShortRequestBody {
|
||||
int offset = 0;
|
||||
|
||||
while (!closed) {
|
||||
err.println("Server: waiting for connection");
|
||||
try (Socket s = ss.accept()) {
|
||||
err.println("Server: got connection");
|
||||
InputStream is = s.getInputStream();
|
||||
readRequestHeaders(is);
|
||||
try {
|
||||
String headers = readRequestHeaders(is);
|
||||
if (headers == null) continue;
|
||||
} catch (SocketException ex) {
|
||||
err.println("Ignoring unexpected exception while reading headers: " + ex);
|
||||
ex.printStackTrace(err);
|
||||
// proceed in order to update count etc..., even though
|
||||
// we know that read() will fail;
|
||||
}
|
||||
byte[] ba = new byte[1024];
|
||||
|
||||
int length = BODY_LENGTHS[count % 3];
|
||||
length += BODY_OFFSETS[offset];
|
||||
err.println("Server: count=" + count + ", offset=" + offset);
|
||||
err.println("Server: expecting " +length+ " bytes");
|
||||
int read = is.readNBytes(ba, 0, length);
|
||||
err.println("Server: actually read " + read + " bytes");
|
||||
|
||||
// Update the counts before replying, to prevent the
|
||||
// client-side racing reset with this thread.
|
||||
count++;
|
||||
if (count % 6 == 0) // 6 is the number of failure requests per offset
|
||||
offset++;
|
||||
if (count % 42 == 0) {
|
||||
count = 0; // reset, for second iteration
|
||||
offset = 0;
|
||||
int read = 0;
|
||||
try {
|
||||
read = is.readNBytes(ba, 0, length);
|
||||
err.println("Server: actually read " + read + " bytes");
|
||||
} finally {
|
||||
// Update the counts before replying, to prevent the
|
||||
// client-side racing reset with this thread.
|
||||
count++;
|
||||
if (count % 6 == 0) // 6 is the number of failure requests per offset
|
||||
offset++;
|
||||
if (count % 42 == 0) {
|
||||
count = 0; // reset, for second iteration
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (read < length) {
|
||||
// no need to reply, client has already closed
|
||||
// ensure closed
|
||||
if (is.read() != -1)
|
||||
new AssertionError("Unexpected read");
|
||||
new AssertionError("Unexpected read: " + read);
|
||||
} else {
|
||||
OutputStream os = s.getOutputStream();
|
||||
err.println("Server: writing "
|
||||
+ RESPONSE.getBytes(US_ASCII).length + " bytes");
|
||||
os.write(RESPONSE.getBytes(US_ASCII));
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
if (!closed)
|
||||
System.out.println("Unexpected" + e);
|
||||
} catch (Throwable e) {
|
||||
if (!closed) {
|
||||
err.println("Unexpected: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,9 +320,14 @@ public class ShortRequestBody {
|
||||
static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' };
|
||||
|
||||
// Read until the end of a HTTP request headers
|
||||
static void readRequestHeaders(InputStream is) throws IOException {
|
||||
int requestEndCount = 0, r;
|
||||
static String readRequestHeaders(InputStream is) throws IOException {
|
||||
int requestEndCount = 0, r, eol = -1;
|
||||
StringBuilder headers = new StringBuilder();
|
||||
while ((r = is.read()) != -1) {
|
||||
if (r == '\r' && eol < 0) {
|
||||
eol = headers.length();
|
||||
}
|
||||
headers.append((char) r);
|
||||
if (r == requestEnd[requestEndCount]) {
|
||||
requestEndCount++;
|
||||
if (requestEndCount == 4) {
|
||||
@ -318,6 +337,11 @@ public class ShortRequestBody {
|
||||
requestEndCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eol <= 0) return null;
|
||||
String requestLine = headers.toString().substring(0, eol);
|
||||
if (!requestLine.contains(MARKER)) return null;
|
||||
return headers.toString();
|
||||
}
|
||||
|
||||
static int fileSize(Path p) {
|
||||
|
@ -57,6 +57,8 @@ import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.test.lib.net.SimpleSSLContext;
|
||||
import org.testng.ITestContext;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
@ -106,6 +108,13 @@ public class ShortResponseBody {
|
||||
};
|
||||
final ExecutorService service = Executors.newCachedThreadPool(factory);
|
||||
|
||||
@BeforeMethod
|
||||
void beforeMethod(ITestContext context) {
|
||||
if (context.getFailedTests().size() > 0) {
|
||||
throw new RuntimeException("some tests failed");
|
||||
}
|
||||
}
|
||||
|
||||
@DataProvider(name = "sanity")
|
||||
public Object[][] sanity() {
|
||||
return new Object[][]{
|
||||
@ -129,7 +138,7 @@ public class ShortResponseBody {
|
||||
}
|
||||
|
||||
@DataProvider(name = "uris")
|
||||
public Object[][] variants() {
|
||||
public Object[][] variants(ITestContext context) {
|
||||
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
|
||||
@ -188,6 +197,13 @@ public 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][];
|
||||
}
|
||||
|
||||
List<Object[]> list = new ArrayList<>();
|
||||
Arrays.asList(cases).stream()
|
||||
.map(e -> new Object[] {e[0], e[1], true}) // reuse client
|
||||
@ -469,7 +485,9 @@ public class ShortResponseBody {
|
||||
try {
|
||||
ss.close();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Unexpected", e);
|
||||
out.println("Unexpected exception while closing server: " + e);
|
||||
e.printStackTrace(out);
|
||||
throw new UncheckedIOException("Unexpected: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -494,9 +512,12 @@ public class ShortResponseBody {
|
||||
((SSLSocket)s).startHandshake();
|
||||
}
|
||||
out.println("Server: got connection, closing immediately ");
|
||||
} catch (IOException e) {
|
||||
if (!closed)
|
||||
throw new UncheckedIOException("Unexpected", e);
|
||||
} catch (Throwable e) {
|
||||
if (!closed) {
|
||||
out.println("Unexpected exception in server: " + e);
|
||||
e.printStackTrace(out);
|
||||
throw new RuntimeException("Unexpected: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -565,9 +586,12 @@ public class ShortResponseBody {
|
||||
os.write(responseBytes[i]);
|
||||
os.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!closed)
|
||||
throw new UncheckedIOException("Unexpected", e);
|
||||
} catch (Throwable e) {
|
||||
if (!closed) {
|
||||
out.println("Unexpected exception in server: " + e);
|
||||
e.printStackTrace(out);
|
||||
throw new RuntimeException("Unexpected: " + e, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user