You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2025/01/22 12:48:09 UTC
(sling-org-apache-sling-connection-timeout-agent) branch master updated: SLING-12617 - Internal error when running the connection timeout agent with Java 17 or 21 (#10)
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-connection-timeout-agent.git
The following commit(s) were added to refs/heads/master by this push:
new 10a6bd0 SLING-12617 - Internal error when running the connection timeout agent with Java 17 or 21 (#10)
10a6bd0 is described below
commit 10a6bd027e9d7addffa79f3486417664544befdf
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Wed Jan 22 13:48:04 2025 +0100
SLING-12617 - Internal error when running the connection timeout agent with Java 17 or 21 (#10)
The first step is to get a working CI build:
- restrict build to Java 11 only
- update Pax-Exam to access Maven Central over HTTPs
- update bundles to satisfy new Pax-Exam requirements
- stop using Maven Central to simulate connection timeouts, it fails on Jenkins.
- chore: replace 'tt' with 'code' in Javadoc
- use loopback addresses explicitly and avoid hostnames
- Skip the connect timeout tests on Windows
- adjust OkHttp timeout message so it captures the Windows Java 11 output.
---
.sling-module.json | 5 +
pom.xml | 6 +-
.../org/apache/sling/cta/impl/AgentInfoMBean.java | 2 +-
.../cta/impl/HttpClient3TimeoutTransformer.java | 4 +-
.../cta/impl/HttpClient4TimeoutTransformer.java | 4 +-
.../sling/cta/impl/JavaNetTimeoutTransformer.java | 6 +-
src/main/java/org/apache/sling/cta/impl/Log.java | 8 +-
.../sling/cta/impl/OkHttpTimeoutTransformer.java | 4 +-
.../java/org/apache/sling/cta/impl/AgentIT.java | 31 +++---
...erverExtension.java => DelayingHttpServer.java} | 68 +++---------
.../org/apache/sling/cta/impl/ErrorDescriptor.java | 6 +-
.../sling/cta/impl/MisbehavingServerControl.java | 7 ++
.../sling/cta/impl/MisbehavingServerExtension.java | 116 +++++++++++++--------
.../java/org/apache/sling/cta/impl/OsgiIT.java | 33 +++++-
14 files changed, 167 insertions(+), 133 deletions(-)
diff --git a/.sling-module.json b/.sling-module.json
new file mode 100644
index 0000000..3c6d326
--- /dev/null
+++ b/.sling-module.json
@@ -0,0 +1,5 @@
+{
+ "jenkins": {
+ "jdks": [ 11 ]
+ }
+}
diff --git a/pom.xml b/pom.xml
index 77fdaf8..c4431e5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -173,7 +173,7 @@
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
- <version>6.0.3</version>
+ <version>7.0.5</version>
<scope>test</scope>
</dependency>
<!-- jacoco agent is manually added to the tests -->
@@ -186,6 +186,6 @@
</dependency>
</dependencies>
<properties>
- <pax-exam.version>4.13.0</pax-exam.version>
+ <pax-exam.version>4.14.0</pax-exam.version>
</properties>
-</project>
\ No newline at end of file
+</project>
diff --git a/src/main/java/org/apache/sling/cta/impl/AgentInfoMBean.java b/src/main/java/org/apache/sling/cta/impl/AgentInfoMBean.java
index 294c012..5e40544 100644
--- a/src/main/java/org/apache/sling/cta/impl/AgentInfoMBean.java
+++ b/src/main/java/org/apache/sling/cta/impl/AgentInfoMBean.java
@@ -17,7 +17,7 @@
package org.apache.sling.cta.impl;
/**
- * Exposes runtime information about the agent using <tt>JMX</tt>.
+ * Exposes runtime information about the agent using <code>JMX</code>.
*
*/
public interface AgentInfoMBean {
diff --git a/src/main/java/org/apache/sling/cta/impl/HttpClient3TimeoutTransformer.java b/src/main/java/org/apache/sling/cta/impl/HttpClient3TimeoutTransformer.java
index c1486e6..32e6add 100644
--- a/src/main/java/org/apache/sling/cta/impl/HttpClient3TimeoutTransformer.java
+++ b/src/main/java/org/apache/sling/cta/impl/HttpClient3TimeoutTransformer.java
@@ -25,8 +25,8 @@ import javassist.bytecode.Descriptor;
/**
* Sets timeouts for HTTP calls done using <em>Apache Commons HttpClient 3.x</em>
*
- * <p>It inserts two calls in <tt>org.apache.commons.httpclient.params.DefaultHttpParamsFactory.createParams</tt> that set
- * default values for <tt>http.connection.timeout</tt> and <tt>http.socket.timeout</tt>.</p>
+ * <p>It inserts two calls in <code>org.apache.commons.httpclient.params.DefaultHttpParamsFactory.createParams</code> that set
+ * default values for <code>http.connection.timeout</code> and <code>http.socket.timeout</code>.</p>
*/
public class HttpClient3TimeoutTransformer extends MBeanAwareTimeoutTransformer {
diff --git a/src/main/java/org/apache/sling/cta/impl/HttpClient4TimeoutTransformer.java b/src/main/java/org/apache/sling/cta/impl/HttpClient4TimeoutTransformer.java
index 8ab7d8e..d67db34 100644
--- a/src/main/java/org/apache/sling/cta/impl/HttpClient4TimeoutTransformer.java
+++ b/src/main/java/org/apache/sling/cta/impl/HttpClient4TimeoutTransformer.java
@@ -21,8 +21,8 @@ import javassist.bytecode.Descriptor;
/**
* Sets timeouts for HTTP calls done using <em>Apache HttpComponents Client 4.x</em>
*
- * <p>It inserts two calls to <tt>org.apache.http.client.config.RequestConfig$Builder</tt> that set default
- * values for <tt>connectTimeout</tt> and <tt>socketTimeout</tt>.</p>
+ * <p>It inserts two calls to <code>org.apache.http.client.config.RequestConfig$Builder</code> that set default
+ * values for <code>connectTimeout</code> and <code>socketTimeout</code>.</p>
*/
public class HttpClient4TimeoutTransformer extends UpdateFieldsInConstructorTimeoutTransformer {
diff --git a/src/main/java/org/apache/sling/cta/impl/JavaNetTimeoutTransformer.java b/src/main/java/org/apache/sling/cta/impl/JavaNetTimeoutTransformer.java
index 302c400..5dceaba 100644
--- a/src/main/java/org/apache/sling/cta/impl/JavaNetTimeoutTransformer.java
+++ b/src/main/java/org/apache/sling/cta/impl/JavaNetTimeoutTransformer.java
@@ -25,10 +25,10 @@ import javassist.CtMethod;
import javassist.bytecode.Descriptor;
/**
- * Sets timeouts for HTTP calls done using <tt>java.net.URL</tt>/<tt>java.net.URLConnection</tt>.
+ * Sets timeouts for HTTP calls done using <code>java.net.URL</code>/<code>java.net.URLConnection</code>.
*
- * <p>It transforms calls to <tt>connect</tt> methods of internal URL connection classes to set the
- * connect and read timeout in case they have the default value of <tt>0</tt>.</p>
+ * <p>It transforms calls to <code>connect</code> methods of internal URL connection classes to set the
+ * connect and read timeout in case they have the default value of <code>0</code>.</p>
*
* @see URLConnection#getConnectTimeout()
* @see URLConnection#getReadTimeout()
diff --git a/src/main/java/org/apache/sling/cta/impl/Log.java b/src/main/java/org/apache/sling/cta/impl/Log.java
index 8826461..aa8df74 100644
--- a/src/main/java/org/apache/sling/cta/impl/Log.java
+++ b/src/main/java/org/apache/sling/cta/impl/Log.java
@@ -37,7 +37,7 @@ abstract class Log {
/**
* Configures the global logger instance
*
- * @param spec the logger spec, <tt>v</tt> for a console log, anything else for a no-op log
+ * @param spec the logger spec, <code>v</code> for a console log, anything else for a no-op log
*/
public static void configure(String spec) {
@@ -70,7 +70,7 @@ abstract class Log {
*
* </p>
*
- * <p>The line separator <tt>%n</tt> is automatically appended to the message.</p>
+ * <p>The line separator <code>%n</code> is automatically appended to the message.</p>
*
* @param msg the message
* @param args the arguments
@@ -80,9 +80,9 @@ abstract class Log {
public abstract void trace(String msg, Object... args);
/**
- * Prints the throwable stack trace and throws a <tt>RuntimeException</tt>
+ * Prints the throwable stack trace and throws a <code>RuntimeException</code>
*
- * @param message the message to include in the <tt>RuntimeException</tt>
+ * @param message the message to include in the <code>RuntimeException</code>
* @param t the throwable to print the stack trace for
*/
public abstract void fatal(String message, Throwable t);
diff --git a/src/main/java/org/apache/sling/cta/impl/OkHttpTimeoutTransformer.java b/src/main/java/org/apache/sling/cta/impl/OkHttpTimeoutTransformer.java
index 7be4cc6..1007805 100644
--- a/src/main/java/org/apache/sling/cta/impl/OkHttpTimeoutTransformer.java
+++ b/src/main/java/org/apache/sling/cta/impl/OkHttpTimeoutTransformer.java
@@ -21,8 +21,8 @@ import javassist.bytecode.Descriptor;
/**
* Sets timeouts for HTTP calls done using <em>OkHttp 3.x</em>
*
- * <p>It inserts two calls to <tt>okhttp3.OkHttpClient$Builder</tt> that set default
- * values for <tt>connectTimeout</tt> and <tt>readTimeout</tt>.</p>
+ * <p>It inserts two calls to <code>okhttp3.OkHttpClient$Builder</code> that set default
+ * values for <code>connectTimeout</code> and <code>readTimeout</code>.</p>
*/
public class OkHttpTimeoutTransformer extends UpdateFieldsInConstructorTimeoutTransformer {
diff --git a/src/test/java/org/apache/sling/cta/impl/AgentIT.java b/src/test/java/org/apache/sling/cta/impl/AgentIT.java
index eaeb63a..b2c01ee 100644
--- a/src/test/java/org/apache/sling/cta/impl/AgentIT.java
+++ b/src/test/java/org/apache/sling/cta/impl/AgentIT.java
@@ -41,6 +41,8 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.sling.cta.impl.HttpClientLauncher.ClientType;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -52,7 +54,7 @@ import org.slf4j.LoggerFactory;
/**
* Validates that accessing URLs that exhibit connection problems results in a timeouts being fired when the agent is used
*
- * <p>This test validates that the agent works when statically loaded, i.e. with a <tt>-javaagent:</tt> flag
+ * <p>This test validates that the agent works when statically loaded, i.e. with a <code>-javaagent:</code> flag
* passed to the JVM. As such it requires launching a new JVM instance each time, otherwise the results are
* not valid.</p>
*
@@ -76,8 +78,8 @@ public class AgentIT {
errorDescriptors.put(JavaNet, new ErrorDescriptor(SocketTimeoutException.class, "connect timed out", "Read timed out"));
errorDescriptors.put(HC3, new ErrorDescriptor(ConnectTimeoutException.class, "The host did not accept the connection within timeout of 3000 ms", "Read timed out"));
errorDescriptors.put(HC4, new ErrorDescriptor(org.apache.http.conn.ConnectTimeoutException.class,
- "Connect to repo1.maven.org:81 \\[.*\\] failed: connect timed out", "Read timed out"));
- errorDescriptors.put(OkHttp, new ErrorDescriptor(SocketTimeoutException.class, "connect timed out", "timeout"));
+ "Connect to 127\\.0\\.0\\.1:[0-9]+ \\[.*\\] failed: connect timed out", "Read timed out"));
+ errorDescriptors.put(OkHttp, new ErrorDescriptor(SocketTimeoutException.class, "connect timed out", "(timeout|Read timed out)"));
}
/**
@@ -96,7 +98,7 @@ public class AgentIT {
*/
static List<Arguments> argumentsMatrix() {
- List<Arguments> args = new ArrayList<Arguments>();
+ List<Arguments> args = new ArrayList<>();
TestTimeouts clientLower = new TestTimeouts.Builder()
.agentTimeouts(Duration.ofMinutes(1), Duration.ofMinutes(1))
@@ -112,23 +114,23 @@ public class AgentIT {
/**
- * Validates that connecting to a unaccessible port on an existing port fails with a connect
+ * Validates that connecting to a unaccessible port on localhost fails with a connect
* timeout exception
*
- * <p>It is surprisingly hard to simulate a connnection timeout. The most reliable way seems to
- * be to get a firewall to drop packets, but this is very hard to do portably and safely
- * in a unit test. The least bad possible solution is to access an URL that we know will timeout
- * and that is able to sustain additional traffic. Maven Central is a good candidate for that.</p>
+ * <p>This test is disabled on Windows because the {@link MisbehavingServerControl} cannot generate connection
+ * timeouts. The TCP/IP stack seems to behave differently on Windows vs Linux when the backlog is full. On Linux
+ * a connection timeout is triggered, while on Windows the connection is refused.</p
*
* @throws IOException various I/O problems
*/
@ParameterizedTest
@MethodSource("argumentsMatrix")
- public void connectTimeout(ClientType clientType, TestTimeouts timeouts) throws IOException {
+ @DisabledOnOs(OS.WINDOWS)
+ public void connectTimeout(ClientType clientType, TestTimeouts timeouts, MisbehavingServerControl server) throws IOException {
ErrorDescriptor ed = requireNonNull(errorDescriptors.get(clientType), "Unhandled clientType " + clientType);
RecordedThrowable error = assertTimeout(ofSeconds(EXECUTION_TIMEOUT_SECONDS),
- () -> runTest("http://repo1.maven.org:81", clientType, timeouts, false));
+ () -> runTest("http://127.0.0.1:" + server.getConnectTimeoutLocalPort(), clientType, timeouts, false));
assertEquals(ed.connectTimeoutClass.getName(), error.className);
assertTrue(error.message.matches(ed.connectTimeoutMessageRegex),
@@ -147,10 +149,11 @@ public class AgentIT {
ErrorDescriptor ed = requireNonNull(errorDescriptors.get(clientType), "Unhandled clientType " + clientType);
RecordedThrowable error = assertTimeout(ofSeconds(EXECUTION_TIMEOUT_SECONDS),
- () -> runTest("http://localhost:" + server.getLocalPort(), clientType, timeouts, false));
+ () -> runTest("http://127.0.0.1:" + server.getLocalPort(), clientType, timeouts, false));
assertEquals(SocketTimeoutException.class.getName(), error.className);
- assertEquals(ed.readTimeoutMessage, error.message);
+ assertTrue(error.message.matches(ed.readTimeoutRegex),
+ "Actual message " + error.message + " did not match regex " + ed.readTimeoutRegex);
}
@ParameterizedTest
@@ -161,7 +164,7 @@ public class AgentIT {
server.setHandleDelay(Duration.ofMillis(100));
assertTimeout(ofSeconds(EXECUTION_TIMEOUT_SECONDS),
- () ->runTest("http://localhost:" + server.getLocalPort(), clientType, TestTimeouts.DEFAULT, true));
+ () ->runTest("http://127.0.0.1:" + server.getLocalPort(), clientType, TestTimeouts.DEFAULT, true));
}
private RecordedThrowable runTest(String urlSpec, ClientType clientType, TestTimeouts timeouts, boolean expectSuccess) throws IOException, InterruptedException {
diff --git a/src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java b/src/test/java/org/apache/sling/cta/impl/DelayingHttpServer.java
similarity index 53%
copy from src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java
copy to src/test/java/org/apache/sling/cta/impl/DelayingHttpServer.java
index 780c104..874c7fc 100644
--- a/src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java
+++ b/src/test/java/org/apache/sling/cta/impl/DelayingHttpServer.java
@@ -17,6 +17,8 @@
package org.apache.sling.cta.impl;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.time.Duration;
import javax.servlet.ServletException;
@@ -27,64 +29,28 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.junit.jupiter.api.extension.AfterEachCallback;
-import org.junit.jupiter.api.extension.BeforeEachCallback;
-import org.junit.jupiter.api.extension.ExtensionContext;
-import org.junit.jupiter.api.extension.ParameterContext;
-import org.junit.jupiter.api.extension.ParameterResolutionException;
-import org.junit.jupiter.api.extension.ParameterResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
- * Provides an Jetty-based local server that can be configured to timeout
- *
- * <p>After extending a JUnit Jupiter test with this extension, any parameter of type {@link MisbehavingServerControl}
- * will be resolved.</p>
- *
- */
-class MisbehavingServerExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver, MisbehavingServerControl {
-
- private static final Duration DEFAULT_HANDLE_DELAY = Duration.ofSeconds(10);
+public class DelayingHttpServer {
private final Logger logger = LoggerFactory.getLogger(getClass());
+ private Duration handleDelay;
- public int getLocalPort() {
- return ((ServerConnector) server.getConnectors()[0]).getLocalPort();
+ public DelayingHttpServer(Duration handleDelay) {
+ this.handleDelay = handleDelay;
}
private Server server;
- private Duration handleDelay = DEFAULT_HANDLE_DELAY;
-
- @Override
- public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
- throws ParameterResolutionException {
- return parameterContext.getParameter().getType() == MisbehavingServerControl.class;
- }
-
- @Override
- public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
- throws ParameterResolutionException {
- if ( parameterContext.getParameter().getType() == MisbehavingServerControl.class )
- return this;
-
- throw new ParameterResolutionException("Unable to get a " + MisbehavingServerControl.class.getSimpleName() + " instance for " + parameterContext);
- }
-
- @Override
- public void beforeEach(ExtensionContext context) throws Exception {
-
- // reset the delay before each execution to make test logic simpler
- handleDelay = DEFAULT_HANDLE_DELAY;
-
- server = new Server(0);
+ public void start() throws Exception {
+ server = new Server(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
server.setHandler(new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
- logger.info("Waiting for " + handleDelay + " before handling");
+ logger.info("Waiting for {} before handling", handleDelay);
try {
Thread.sleep(handleDelay.toMillis());
} catch (InterruptedException e) {
@@ -102,19 +68,17 @@ class MisbehavingServerExtension implements BeforeEachCallback, AfterEachCallbac
server.start();
}
-
- @Override
- public void afterEach(ExtensionContext context) throws Exception {
- if ( server == null )
- return;
- try {
+
+ public void stop() throws Exception {
+ if (server != null) {
server.stop();
- } catch (Exception e) {
- logger.info("Failed shutting down server", e);
}
}
- @Override
+ public int getLocalPort() {
+ return ((ServerConnector) server.getConnectors()[0]).getLocalPort();
+ }
+
public void setHandleDelay(Duration handleDelay) {
this.handleDelay = handleDelay;
}
diff --git a/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java b/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
index d70b76f..0a1865e 100644
--- a/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
+++ b/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
@@ -26,12 +26,12 @@ import org.apache.sling.cta.impl.HttpClientLauncher.ClientType;
class ErrorDescriptor {
Class<? extends IOException> connectTimeoutClass;
String connectTimeoutMessageRegex;
- String readTimeoutMessage;
+ String readTimeoutRegex;
public ErrorDescriptor(Class<? extends IOException> connectTimeoutClass, String connectTimeoutMessageRegex,
- String readTimeoutMessage) {
+ String readTimeoutRegex) {
this.connectTimeoutClass = connectTimeoutClass;
this.connectTimeoutMessageRegex = connectTimeoutMessageRegex;
- this.readTimeoutMessage = readTimeoutMessage;
+ this.readTimeoutRegex = readTimeoutRegex;
}
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/cta/impl/MisbehavingServerControl.java b/src/test/java/org/apache/sling/cta/impl/MisbehavingServerControl.java
index d18ac2c..10465c5 100644
--- a/src/test/java/org/apache/sling/cta/impl/MisbehavingServerControl.java
+++ b/src/test/java/org/apache/sling/cta/impl/MisbehavingServerControl.java
@@ -42,4 +42,11 @@ public interface MisbehavingServerControl {
* @param handleDelay the new duration
*/
void setHandleDelay(Duration handleDelay);
+
+ /**
+ * Returns the port on which a local server that does not answer to connections is bound
+ *
+ * @return the port
+ */
+ int getConnectTimeoutLocalPort();
}
diff --git a/src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java b/src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java
index 780c104..b65fad4 100644
--- a/src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java
+++ b/src/test/java/org/apache/sling/cta/impl/MisbehavingServerExtension.java
@@ -17,16 +17,14 @@
package org.apache.sling.cta.impl;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
@@ -49,13 +47,10 @@ class MisbehavingServerExtension implements BeforeEachCallback, AfterEachCallbac
private final Logger logger = LoggerFactory.getLogger(getClass());
- public int getLocalPort() {
- return ((ServerConnector) server.getConnectors()[0]).getLocalPort();
- }
-
- private Server server;
+ private DelayingHttpServer server;
- private Duration handleDelay = DEFAULT_HANDLE_DELAY;
+ private ServerSocket ss;
+ private List<Socket> sockets = new ArrayList<>();
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
@@ -75,47 +70,82 @@ class MisbehavingServerExtension implements BeforeEachCallback, AfterEachCallbac
@Override
public void beforeEach(ExtensionContext context) throws Exception {
- // reset the delay before each execution to make test logic simpler
- handleDelay = DEFAULT_HANDLE_DELAY;
+ server = new DelayingHttpServer(DEFAULT_HANDLE_DELAY);
+ server.start();
+
+ // an undocumented feature of ServerSocket is that the backlog size is quietly adjusted
+ // to be at least 50
+ int backlog = 50;
- server = new Server(0);
- server.setHandler(new AbstractHandler() {
-
- @Override
- public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
- logger.info("Waiting for " + handleDelay + " before handling");
- try {
- Thread.sleep(handleDelay.toMillis());
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return;
+ // create a server socket that will not accept connections. We do this by controlling the
+ // backlog size and making sure that it is full before running the test
+ ss = new ServerSocket(0, backlog, InetAddress.getLoopbackAddress());
+
+ CountDownLatch waitForConnection = new CountDownLatch(1);
+
+ new Thread(() -> {
+ int activeConnection = 0;
+ try {
+ // completely tie up the server: 1 active connection + backlog full
+ for (int i = 0; i < backlog + 1; i++) {
+ activeConnection = i;
+ sockets.add(new Socket("127.0.0.1", ss.getLocalPort()));
}
-
- response.setStatus(HttpServletResponse.SC_NO_CONTENT);
- if ( baseRequest.getHeader("User-Agent") != null )
- response.addHeader("Original-User-Agent", baseRequest.getHeader("User-Agent"));
- baseRequest.setHandled(true);
- logger.info("Handled");
+ logger.info("Keeping connections to port {} unavailable" , ss.getLocalPort());
+ waitForConnection.countDown();
+ // Keep the connection open to fill the backlog
+ Thread.sleep(Long.MAX_VALUE);
+ } catch ( InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } catch (IOException e) {
+ logger.info("Failed connecting to server, active connection was {}", activeConnection, e);
+ waitForConnection.countDown();
}
- });
+ }).start();
- server.start();
+ waitForConnection.await();
}
@Override
public void afterEach(ExtensionContext context) throws Exception {
- if ( server == null )
- return;
- try {
- server.stop();
- } catch (Exception e) {
- logger.info("Failed shutting down server", e);
+ if ( server != null ) {
+ try {
+ server.stop();
+ } catch (Exception e) {
+ logger.info("Failed shutting down server", e);
+ }
+ }
+
+ if (ss != null) {
+ try {
+ ss.close();
+ } catch (IOException e) {
+ logger.info("Failed closing server socket", e);
+ }
+ }
+
+ for (Socket s : sockets) {
+ try {
+ s.close();
+ } catch (IOException e) {
+ logger.info("Failed closing socket", e);
+ }
}
+ sockets.clear();
}
@Override
public void setHandleDelay(Duration handleDelay) {
- this.handleDelay = handleDelay;
+ server.setHandleDelay(handleDelay);
+ }
+
+ @Override
+ public int getLocalPort() {
+ return server.getLocalPort();
+ }
+
+ @Override
+ public int getConnectTimeoutLocalPort() {
+ return ss.getLocalPort();
}
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/cta/impl/OsgiIT.java b/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
index 56264db..17b2752 100644
--- a/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
+++ b/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
@@ -23,20 +23,23 @@ import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.vmOption;
import java.io.IOException;
+import java.net.SocketTimeoutException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
+import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
@@ -53,6 +56,8 @@ import org.ops4j.pax.exam.junit.PaxExam;
@RunWith(PaxExam.class)
public class OsgiIT {
+ private DelayingHttpServer server;
+
@Configuration
public Option[] config() throws IOException {
@@ -69,18 +74,38 @@ public class OsgiIT {
return options(
junitBundles(),
+ mavenBundle("org.apache.felix", "org.apache.felix.configadmin", "1.9.26"),
mavenBundle("org.apache.httpcomponents", "httpcore-osgi", "4.4.12"),
mavenBundle("org.apache.httpcomponents", "httpclient-osgi", "4.5.10"),
- vmOption("-javaagent:" + agentCandidates.get(0) +"=1,1,v")
+ mavenBundle("org.apache.felix", "org.apache.felix.http.servlet-api", "3.0.0"),
+ mavenBundle("org.apache.felix","org.apache.felix.http.jetty","5.1.26"),
+ vmOption("-javaagent:" + agentCandidates.get(0) +"=10000,1,v") // large connect timeout, very small read timeout
);
}
+
+ @Before
+ public void startHttpServer() throws Exception {
+ server = new DelayingHttpServer(Duration.ofSeconds(1));
+ server.start();
+ }
+
+ @After
+ public void stopHttpServer() {
+ if (server != null) {
+ try {
+ server.stop();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
- @Test(expected = ConnectTimeoutException.class)
+ @Test(expected = SocketTimeoutException.class)
public void callTimesOut() throws IOException {
try ( CloseableHttpClient httpclient = HttpClients.createDefault() ) {
// the used host does not really matter, the connect timeout of 1 ms
// should kick in almost instantly
- HttpGet get = new HttpGet("https://repo1.maven.org/");
+ HttpGet get = new HttpGet("http://127.0.0.1:" + server.getLocalPort() + "/");
try ( CloseableHttpResponse response = httpclient.execute(get)) {
fail("Request should have failed");
}