Revised external caching client tests

This commit is contained in:
Oleg Kalnichevski 2023-12-24 11:02:47 +01:00
parent c3d99b130c
commit 810d7b0568
2 changed files with 95 additions and 132 deletions

View File

@ -26,14 +26,10 @@
*/ */
package org.apache.hc.client5.testing.external; package org.apache.hc.client5.testing.external;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
@ -48,9 +44,10 @@ import org.apache.hc.client5.http.impl.cache.HeapResourceFactory;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.HttpVersion;
import org.apache.hc.core5.http2.HttpVersionPolicy; import org.apache.hc.core5.http2.HttpVersionPolicy;
@ -99,26 +96,35 @@ public class CachingHttpAsyncClientCompatibilityTest {
this.client = CachingHttpAsyncClients.custom() this.client = CachingHttpAsyncClients.custom()
.setCacheConfig(CacheConfig.custom() .setCacheConfig(CacheConfig.custom()
.setMaxObjectSize(20480) .setMaxObjectSize(20480)
.setHeuristicCachingEnabled(true)
.build()) .build())
.setResourceFactory(HeapResourceFactory.INSTANCE) .setResourceFactory(HeapResourceFactory.INSTANCE)
.setConnectionManager(this.connManager) .setConnectionManager(this.connManager)
.build(); .build();
} }
void shutdown() throws Exception { void shutdown() throws Exception {
client.close(); client.close();
} }
enum TestResult {OK, NOK} enum TestResult {OK, NOK}
private void logResult(final TestResult result, final HttpRequest request, final String message) { private void logResult(final TestResult result,
final HttpRequest request,
final HttpResponse response,
final String message) {
final StringBuilder buf = new StringBuilder(); final StringBuilder buf = new StringBuilder();
buf.append(result); buf.append(result);
if (buf.length() == 2) { if (buf.length() == 2) {
buf.append(" "); buf.append(" ");
} }
buf.append(": ").append(target); buf.append(": ");
if (response != null && response.getVersion() != null) {
buf.append(response.getVersion()).append(" ");
} else {
buf.append(protocolVersion).append(" ");
}
buf.append(target);
buf.append(": "); buf.append(": ");
buf.append(request.getMethod()).append(" ").append(request.getRequestUri()); buf.append(request.getMethod()).append(" ").append(request.getRequestUri());
if (message != null && !TextUtils.isBlank(message)) { if (message != null && !TextUtils.isBlank(message)) {
@ -127,7 +133,7 @@ public class CachingHttpAsyncClientCompatibilityTest {
System.out.println(buf); System.out.println(buf);
} }
void execute() throws Exception { void execute() throws InterruptedException {
client.start(); client.start();
// Initial ping // Initial ping
@ -142,113 +148,90 @@ public class CachingHttpAsyncClientCompatibilityTest {
final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()); final SimpleHttpResponse response = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
final int code = response.getCode(); final int code = response.getCode();
if (code == HttpStatus.SC_OK) { if (code == HttpStatus.SC_OK) {
logResult(TestResult.OK, options, Objects.toString(response.getFirstHeader("server"))); logResult(TestResult.OK, options, response, Objects.toString(response.getFirstHeader("server")));
} else { } else {
logResult(TestResult.NOK, options, "(status " + code + ")"); logResult(TestResult.NOK, options, response, "(status " + code + ")");
} }
} catch (final ExecutionException ex) { } catch (final ExecutionException ex) {
final Throwable cause = ex.getCause(); final Throwable cause = ex.getCause();
logResult(TestResult.NOK, options, "(" + cause.getMessage() + ")"); logResult(TestResult.NOK, options, null, "(" + cause.getMessage() + ")");
} catch (final TimeoutException ex) { } catch (final TimeoutException ex) {
logResult(TestResult.NOK, options, "(time out)"); logResult(TestResult.NOK, options, null, "(time out)");
} }
} }
// GET with links
// GET from cache
{ {
connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND); connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
final HttpCacheContext context = HttpCacheContext.create(); final HttpCacheContext context = HttpCacheContext.create();
final Pattern linkPattern = Pattern.compile("^<(.*)>;rel=preload$"); final String[] links = {"/", "/css/hc-maven.css", "/images/logos/httpcomponents.png"};
final List<String> links = new ArrayList<>();
final SimpleHttpRequest getRoot1 = SimpleRequestBuilder.get()
.setHttpHost(target)
.setPath("/")
.build();
final Future<SimpleHttpResponse> future1 = client.execute(getRoot1, context, null);
try {
final SimpleHttpResponse response = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus);
} else {
logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")");
}
for (final Header header: response.getHeaders("Link")) {
final Matcher matcher = linkPattern.matcher(header.getValue());
if (matcher.matches()) {
links.add(matcher.group(1));
}
}
} catch (final ExecutionException ex) {
final Throwable cause = ex.getCause();
logResult(TestResult.NOK, getRoot1, "(" + cause.getMessage() + ")");
} catch (final TimeoutException ex) {
logResult(TestResult.NOK, getRoot1, "(time out)");
}
for (final String link: links) { for (final String link: links) {
final SimpleHttpRequest getLink = SimpleRequestBuilder.get() final SimpleHttpRequest httpGet1 = SimpleRequestBuilder.get()
.setHttpHost(target) .setHttpHost(target)
.setPath(link) .setPath(link)
.build(); .build();
final Future<SimpleHttpResponse> linkFuture = client.execute(getLink, context, null); final Future<SimpleHttpResponse> linkFuture1 = client.execute(httpGet1, context, null);
try { try {
final SimpleHttpResponse response = linkFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()); final SimpleHttpResponse response = linkFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
final int code = response.getCode(); final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus(); final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) { if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
logResult(TestResult.OK, getLink, "200, " + cacheResponseStatus); logResult(TestResult.OK, httpGet1, response, "200, " + cacheResponseStatus);
} else { } else {
logResult(TestResult.NOK, getLink, "(status " + code + ", " + cacheResponseStatus + ")"); logResult(TestResult.NOK, httpGet1, response, "(status " + code + ", " + cacheResponseStatus + ")");
} }
} catch (final ExecutionException ex) { } catch (final ExecutionException ex) {
final Throwable cause = ex.getCause(); final Throwable cause = ex.getCause();
logResult(TestResult.NOK, getLink, "(" + cause.getMessage() + ")"); logResult(TestResult.NOK, httpGet1, null, "(" + cause.getMessage() + ")");
} catch (final TimeoutException ex) { } catch (final TimeoutException ex) {
logResult(TestResult.NOK, getLink, "(time out)"); logResult(TestResult.NOK, httpGet1, null,"(time out)");
}
} }
final SimpleHttpRequest getRoot2 = SimpleRequestBuilder.get() final SimpleHttpRequest httpGet2 = SimpleRequestBuilder.get()
.setHttpHost(target)
.setPath("/")
.build();
final Future<SimpleHttpResponse> future2 = client.execute(getRoot2, context, null);
try {
final SimpleHttpResponse response = future2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus);
} else {
logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")");
}
} catch (final ExecutionException ex) {
final Throwable cause = ex.getCause();
logResult(TestResult.NOK, getRoot2, "(" + cause.getMessage() + ")");
} catch (final TimeoutException ex) {
logResult(TestResult.NOK, getRoot2, "(time out)");
}
for (final String link: links) {
final SimpleHttpRequest getLink = SimpleRequestBuilder.get()
.setHttpHost(target) .setHttpHost(target)
.setPath(link) .setPath(link)
.build(); .build();
final Future<SimpleHttpResponse> linkFuture = client.execute(getLink, context, null); final Future<SimpleHttpResponse> linkFuture2 = client.execute(httpGet2, context, null);
try { try {
final SimpleHttpResponse response = linkFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()); final SimpleHttpResponse response = linkFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
final int code = response.getCode(); final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus(); final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) { if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_HIT) {
logResult(TestResult.OK, getLink, "200, " + cacheResponseStatus); logResult(TestResult.OK, httpGet2, response, "200, " + cacheResponseStatus);
} else { } else {
logResult(TestResult.NOK, getLink, "(status " + code + ", " + cacheResponseStatus + ")"); logResult(TestResult.NOK, httpGet2, response, "(status " + code + ", " + cacheResponseStatus + ")");
} }
} catch (final ExecutionException ex) { } catch (final ExecutionException ex) {
final Throwable cause = ex.getCause(); final Throwable cause = ex.getCause();
logResult(TestResult.NOK, getLink, "(" + cause.getMessage() + ")"); logResult(TestResult.NOK, httpGet2, null, "(" + cause.getMessage() + ")");
} catch (final TimeoutException ex) { } catch (final TimeoutException ex) {
logResult(TestResult.NOK, getLink, "(time out)"); logResult(TestResult.NOK, httpGet2, null,"(time out)");
}
Thread.sleep(2000);
final SimpleHttpRequest httpGet3 = SimpleRequestBuilder.get()
.setHttpHost(target)
.setPath(link)
.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=0")
.build();
final Future<SimpleHttpResponse> linkFuture3 = client.execute(httpGet3, context, null);
try {
final SimpleHttpResponse response = linkFuture3.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
logResult(TestResult.OK, httpGet3, response, "200, " + cacheResponseStatus);
} else {
logResult(TestResult.NOK, httpGet3, response, "(status " + code + ", " + cacheResponseStatus + ")");
}
} catch (final ExecutionException ex) {
final Throwable cause = ex.getCause();
logResult(TestResult.NOK, httpGet3, null, "(" + cause.getMessage() + ")");
} catch (final TimeoutException ex) {
logResult(TestResult.NOK, httpGet3, null,"(time out)");
} }
} }
} }

View File

@ -26,11 +26,7 @@
*/ */
package org.apache.hc.client5.testing.external; package org.apache.hc.client5.testing.external;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
@ -46,7 +42,7 @@ import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.HttpStatus;
@ -85,6 +81,7 @@ public class CachingHttpClientCompatibilityTest {
this.client = CachingHttpClients.custom() this.client = CachingHttpClients.custom()
.setCacheConfig(CacheConfig.custom() .setCacheConfig(CacheConfig.custom()
.setMaxObjectSize(20480) .setMaxObjectSize(20480)
.setHeuristicCachingEnabled(true)
.build()) .build())
.setResourceFactory(HeapResourceFactory.INSTANCE) .setResourceFactory(HeapResourceFactory.INSTANCE)
.setConnectionManager(this.connManager) .setConnectionManager(this.connManager)
@ -112,7 +109,7 @@ public class CachingHttpClientCompatibilityTest {
System.out.println(buf); System.out.println(buf);
} }
void execute() { void execute() throws InterruptedException {
// Initial ping // Initial ping
{ {
@ -130,73 +127,56 @@ public class CachingHttpClientCompatibilityTest {
logResult(TestResult.NOK, options, "(" + ex.getMessage() + ")"); logResult(TestResult.NOK, options, "(" + ex.getMessage() + ")");
} }
} }
// GET with links // GET from cache
{ {
connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND); connManager.closeIdle(TimeValue.NEG_ONE_MILLISECOND);
final String[] links = {"/", "/css/hc-maven.css", "/images/logos/httpcomponents.png"};
final HttpCacheContext context = HttpCacheContext.create(); final HttpCacheContext context = HttpCacheContext.create();
final Pattern linkPattern = Pattern.compile("^<(.*)>;rel=preload$"); for (final String link: links) {
final List<String> links = new ArrayList<>(); final HttpGet httpGet1 = new HttpGet(link);
final HttpGet getRoot1 = new HttpGet("/"); try (ClassicHttpResponse response = client.executeOpen(target, httpGet1, context)) {
try (ClassicHttpResponse response = client.executeOpen(target, getRoot1, context)) {
final int code = response.getCode(); final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus(); final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
EntityUtils.consume(response.getEntity()); EntityUtils.consume(response.getEntity());
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) { if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus); logResult(TestResult.OK, httpGet1, "200, " + cacheResponseStatus);
} else { } else {
logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")"); logResult(TestResult.NOK, httpGet1, "(status " + code + ", " + cacheResponseStatus + ")");
}
for (final Header header: response.getHeaders("Link")) {
final Matcher matcher = linkPattern.matcher(header.getValue());
if (matcher.matches()) {
links.add(matcher.group(1));
}
} }
} catch (final Exception ex) { } catch (final Exception ex) {
logResult(TestResult.NOK, getRoot1, "(" + ex.getMessage() + ")"); logResult(TestResult.NOK, httpGet1, "(" + ex.getMessage() + ")");
}
final HttpGet httpGet2 = new HttpGet(link);
try (ClassicHttpResponse response = client.executeOpen(target, httpGet2, context)) {
final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
EntityUtils.consume(response.getEntity());
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_HIT) {
logResult(TestResult.OK, httpGet2, "200, " + cacheResponseStatus);
} else {
logResult(TestResult.NOK, httpGet2, "(status " + code + ", " + cacheResponseStatus + ")");
}
} catch (final Exception ex) {
logResult(TestResult.NOK, httpGet2, "(" + ex.getMessage() + ")");
} }
for (final String link: links) { Thread.sleep(2000);
final HttpGet getLink = new HttpGet(link);
try (ClassicHttpResponse response = client.executeOpen(target, getLink, context)) { final HttpGet httpGet3 = new HttpGet(link);
final int code = response.getCode(); httpGet3.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=0");
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus(); try (ClassicHttpResponse response = client.executeOpen(target, httpGet3, context)) {
EntityUtils.consume(response.getEntity());
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.CACHE_MISS) {
logResult(TestResult.OK, getRoot1, "200, " + cacheResponseStatus);
} else {
logResult(TestResult.NOK, getRoot1, "(status " + code + ", " + cacheResponseStatus + ")");
}
} catch (final Exception ex) {
logResult(TestResult.NOK, getLink, "(" + ex.getMessage() + ")");
}
}
final HttpGet getRoot2 = new HttpGet("/");
try (ClassicHttpResponse response = client.executeOpen(target, getRoot2, context)) {
final int code = response.getCode(); final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus(); final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
EntityUtils.consume(response.getEntity()); EntityUtils.consume(response.getEntity());
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) { if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus); logResult(TestResult.OK, httpGet3, "200, " + cacheResponseStatus);
} else { } else {
logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")"); logResult(TestResult.NOK, httpGet3, "(status " + code + ", " + cacheResponseStatus + ")");
} }
} catch (final Exception ex) { } catch (final Exception ex) {
logResult(TestResult.NOK, getRoot2, "(" + ex.getMessage() + ")"); logResult(TestResult.NOK, httpGet3, "(" + ex.getMessage() + ")");
}
for (final String link: links) {
final HttpGet getLink = new HttpGet(link);
try (ClassicHttpResponse response = client.executeOpen(target, getLink, context)) {
final int code = response.getCode();
final CacheResponseStatus cacheResponseStatus = context.getCacheResponseStatus();
EntityUtils.consume(response.getEntity());
if (code == HttpStatus.SC_OK && cacheResponseStatus == CacheResponseStatus.VALIDATED) {
logResult(TestResult.OK, getRoot2, "200, " + cacheResponseStatus);
} else {
logResult(TestResult.NOK, getRoot2, "(status " + code + ", " + cacheResponseStatus + ")");
}
} catch (final Exception ex) {
logResult(TestResult.NOK, getLink, "(" + ex.getMessage() + ")");
} }
} }
} }