KEYCLOAK-14862 Upgrade httpclient test dependency
The new version of httpclient supports handling HTTP 429 errors. This should resolve the sporadic failures in the ReleaseNotesTest in PRs. I also increased the retry count to 5, to make sure the default backoff algorithm in httpclient has room to work effectively.
This commit is contained in:
parent
aecad05a10
commit
8a3fbabf26
3 changed files with 126 additions and 79 deletions
|
@ -119,9 +119,9 @@
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
<artifactId>httpclient</artifactId>
|
<artifactId>httpclient5</artifactId>
|
||||||
<version>4.5.12</version>
|
<version>5.0.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
public static final int HTTP_RETRY = 3;
|
public static final int HTTP_RETRY = 5;
|
||||||
public static final int HTTP_CONNECTION_TIMEOUT = 30000;
|
public static final int HTTP_CONNECTION_TIMEOUT = 30000;
|
||||||
public static final int HTTP_READ_TIMEOUT = 300000;
|
public static final int HTTP_READ_TIMEOUT = 300000;
|
||||||
public static final long LINK_CHECK_EXPIRATION = TimeUnit.DAYS.toMillis(1);
|
public static final long LINK_CHECK_EXPIRATION = TimeUnit.DAYS.toMillis(1);
|
||||||
|
|
|
@ -1,45 +1,77 @@
|
||||||
package org.keycloak.documentation.test.utils;
|
package org.keycloak.documentation.test.utils;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.hc.client5.http.ClientProtocolException;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
import org.apache.http.client.config.CookieSpecs;
|
import org.apache.hc.client5.http.classic.methods.HttpHead;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.http.client.methods.HttpHead;
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
import org.apache.http.cookie.CookieSpec;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
|
||||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
|
import org.apache.hc.core5.http.ParseException;
|
||||||
|
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
|
||||||
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
|
import org.apache.hc.core5.util.TimeValue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.security.cert.X509Certificate;
|
||||||
import java.net.HttpURLConnection;
|
import javax.net.ssl.SSLContext;
|
||||||
import java.net.URL;
|
import javax.net.ssl.SSLException;
|
||||||
import java.net.URLDecoder;
|
import javax.net.ssl.SSLSession;
|
||||||
import java.nio.charset.StandardCharsets;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
public class HttpUtils {
|
public class HttpUtils {
|
||||||
|
|
||||||
|
private CloseableHttpClient client;
|
||||||
|
|
||||||
|
public HttpUtils() {
|
||||||
|
try {
|
||||||
|
client = createClient();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
client.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public Response load(String url) {
|
public Response load(String url) {
|
||||||
CloseableHttpClient client = createClient();
|
return exec(new HttpGet(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response isValid(String url) {
|
||||||
|
return exec(new HttpHead(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response exec(HttpUriRequestBase method) {
|
||||||
Response response = new Response();
|
Response response = new Response();
|
||||||
|
|
||||||
try {
|
HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>() {
|
||||||
HttpGet h = new HttpGet(url);
|
@Override
|
||||||
CloseableHttpResponse r = client.execute(h);
|
public String handleResponse(ClassicHttpResponse r) throws IOException {
|
||||||
int status = r.getStatusLine().getStatusCode();
|
int status = r.getCode();
|
||||||
|
|
||||||
if (status == 200) {
|
if (status == HttpStatus.SC_SUCCESS) {
|
||||||
response.setSuccess(true);
|
response.setSuccess(true);
|
||||||
|
|
||||||
HttpEntity entity = r.getEntity();
|
HttpEntity entity = r.getEntity();
|
||||||
String c = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8);
|
try {
|
||||||
|
String c = entity != null ? EntityUtils.toString(entity) : "";
|
||||||
response.setContent(c);
|
response.setContent(c);
|
||||||
} else if (status == 301 || status == 302) {
|
} catch (ParseException e) {
|
||||||
|
throw new ClientProtocolException(e);
|
||||||
|
}
|
||||||
|
} else if (status / 100 == 3) {
|
||||||
String location = r.getFirstHeader("Location").getValue();
|
String location = r.getFirstHeader("Location").getValue();
|
||||||
response.setRedirectLocation(location);
|
response.setRedirectLocation(location);
|
||||||
response.setSuccess(false);
|
response.setSuccess(false);
|
||||||
|
@ -47,58 +79,73 @@ public class HttpUtils {
|
||||||
response.setError("invalid status code " + status);
|
response.setError("invalid status code " + status);
|
||||||
response.setSuccess(false);
|
response.setSuccess(false);
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.execute(method, responseHandler);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
response.setError("exception " + e.getMessage());
|
response.setError("exception " + e.getMessage());
|
||||||
response.setSuccess(false);
|
response.setSuccess(false);
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
client.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CloseableHttpClient createClient() {
|
private static CloseableHttpClient createClient() throws Exception {
|
||||||
return HttpClientBuilder.create()
|
return HttpClientBuilder.create()
|
||||||
.setRetryHandler(new DefaultHttpRequestRetryHandler(Constants.HTTP_RETRY, true))
|
.setRetryStrategy(new DefaultHttpRequestRetryStrategy(
|
||||||
.setDefaultRequestConfig(
|
Constants.HTTP_RETRY,
|
||||||
RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build()
|
TimeValue.ofSeconds(1L)
|
||||||
|
))
|
||||||
|
.disableCookieManagement()
|
||||||
|
.disableRedirectHandling()
|
||||||
|
.setConnectionManager(
|
||||||
|
PoolingHttpClientConnectionManagerBuilder.create()
|
||||||
|
.setSSLSocketFactory(new NoopSSLConnectionSocketFactory())
|
||||||
|
.build()
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response isValid(String url) {
|
private static class NoopSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
|
||||||
CloseableHttpClient client = createClient();
|
private static SSLContext sslContext;
|
||||||
Response response = new Response();
|
|
||||||
|
|
||||||
|
static {
|
||||||
try {
|
try {
|
||||||
HttpHead h = new HttpHead(url);
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
CloseableHttpResponse r = client.execute(h);
|
sslContext.init(
|
||||||
int status = r.getStatusLine().getStatusCode();
|
null,
|
||||||
|
new X509TrustManager[] {
|
||||||
if (status == 200) {
|
new X509TrustManager() {
|
||||||
response.setSuccess(true);
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
} else if (status == 301 || status == 302) {
|
return null;
|
||||||
String location = r.getFirstHeader("Location").getValue();
|
|
||||||
response.setRedirectLocation(location);
|
|
||||||
response.setSuccess(false);
|
|
||||||
} else {
|
|
||||||
response.setError("invalid status code " + status);
|
|
||||||
response.setSuccess(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
response.setError("exception " + e.getMessage());
|
throw new RuntimeException(e);
|
||||||
response.setSuccess(false);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
client.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
public NoopSSLConnectionSocketFactory() {
|
||||||
|
super(sslContext, new NoopHostnameVerifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verifySession(String hostname, SSLSession sslSession) throws SSLException {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Response {
|
public static class Response {
|
||||||
|
|
Loading…
Reference in a new issue