SLING-9757 Add configurable connection timeout for SlingClient
diff --git a/src/main/java/org/apache/sling/testing/clients/SlingClient.java b/src/main/java/org/apache/sling/testing/clients/SlingClient.java
index 58c4ef3..7a64ddd 100644
--- a/src/main/java/org/apache/sling/testing/clients/SlingClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/SlingClient.java
@@ -16,6 +16,16 @@
*/
package org.apache.sling.testing.clients;
+import static org.apache.http.HttpStatus.SC_CREATED;
+import static org.apache.http.HttpStatus.SC_OK;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequestInterceptor;
@@ -25,6 +35,7 @@
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.RedirectStrategy;
+import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -32,20 +43,15 @@
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.sling.testing.clients.interceptors.DelayRequestInterceptor;
import org.apache.sling.testing.clients.interceptors.TestDescriptionInterceptor;
-import org.apache.sling.testing.clients.util.*;
+import org.apache.sling.testing.clients.util.FormEntityBuilder;
+import org.apache.sling.testing.clients.util.HttpUtils;
+import org.apache.sling.testing.clients.util.JsonUtils;
+import org.apache.sling.testing.clients.util.ServerErrorRetryStrategy;
import org.apache.sling.testing.clients.util.poller.AbstractPoller;
import org.apache.sling.testing.clients.util.poller.Polling;
+import org.apache.sling.testing.timeouts.TimeoutsProvider;
import org.codehaus.jackson.JsonNode;
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-import static org.apache.http.HttpStatus.SC_CREATED;
-import static org.apache.http.HttpStatus.SC_OK;
-
/**
* <p>The Base class for all Integration Test Clients. It provides generic methods to send HTTP requests to a server. </p>
*
@@ -56,6 +62,7 @@
public class SlingClient extends AbstractSlingClient {
public static final String DEFAULT_NODE_TYPE = "sling:OrderedFolder";
+ public static final String CLIENT_CONNECTION_TIMEOUT_PROP = "sling.client.connection.timeout.seconds";
/**
* Constructor used by Builders and adaptTo(). <b>Should never be called directly from the code.</b>
@@ -692,6 +699,17 @@
// HTTP request strategy
httpClientBuilder.setServiceUnavailableRetryStrategy(new ServerErrorRetryStrategy());
+ // connection timeouts
+ int timeoutSeconds = TimeoutsProvider.getInstance().getTimeout(CLIENT_CONNECTION_TIMEOUT_PROP, -1);
+ if (timeoutSeconds > 0) {
+ int timeoutMs = (int)TimeUnit.SECONDS.toMillis(timeoutSeconds);
+ RequestConfig config = RequestConfig.custom()
+ .setConnectTimeout(timeoutMs)
+ .setConnectionRequestTimeout(timeoutMs)
+ .setSocketTimeout(timeoutMs).build();
+ this.httpClientBuilder.setDefaultRequestConfig(config);
+ }
+
return this;
}
diff --git a/src/test/java/org/apache/sling/testing/clients/SlingClientConnectionTimeoutTest.java b/src/test/java/org/apache/sling/testing/clients/SlingClientConnectionTimeoutTest.java
new file mode 100644
index 0000000..58e4570
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/clients/SlingClientConnectionTimeoutTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.sling.testing.clients;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+/**
+ * SLING-9757 verify configurable connection timeout for SlingClient
+ */
+public class SlingClientConnectionTimeoutTest {
+ private static final String GET_TIMEOUT_PATH = "/test/timeout/resource";
+ private static final String OK_RESPONSE = "TEST_OK";
+
+ @ClassRule
+ public static HttpServerRule httpServer = new HttpServerRule() {
+ @Override
+ protected void registerHandlers() throws IOException {
+ serverBootstrap.registerHandler(GET_TIMEOUT_PATH, new HttpRequestHandler() {
+ @Override
+ public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
+ // block for 15 seconds
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(15));
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ response.setEntity(new StringEntity(OK_RESPONSE));
+ }
+ });
+ }
+ };
+
+ /**
+ * Test that a configured connection timeout will kill the client request when it
+ * does not respond quickly enough
+ */
+ @Test
+ public void testConnectionTimeout() throws Exception {
+ String originalValue = System.getProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, null);
+ try {
+ // timeout when the request takes more than 2 second
+ System.setProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, "2");
+ try (SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass")) {
+ // start the client request
+ c.doGet(GET_TIMEOUT_PATH);
+
+ // should not get here
+ fail("Did not recieve the expected SocketTimeoutException");
+ }
+ } catch (Exception e) {
+ Throwable cause = e.getCause();
+ assertTrue("expected a SocketTimeoutException", cause instanceof SocketTimeoutException);
+ } finally {
+ //put the original value back
+ if (originalValue == null) {
+ System.clearProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP);
+ } else {
+ System.setProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, originalValue);
+ }
+ }
+ }
+
+ /**
+ * Test that when no connection timeout is supplied, the client connection waits
+ */
+ @Test
+ public void testConnectionNoTimeout() throws Exception {
+ String originalValue = System.getProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, null);
+ try {
+ // clear out any timeout configuration
+ System.clearProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP);
+
+ try (SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass")) {
+ SlingHttpResponse response = null;
+ CompletableFuture<SlingHttpResponse> endpointCall = CompletableFuture.supplyAsync(() -> {
+ try {
+ return c.doGet(GET_TIMEOUT_PATH);
+ } catch (ClientException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ return null;
+ });
+
+ try {
+ response = endpointCall.get(2, TimeUnit.SECONDS);
+ assertNull("Did not expect a response from the endpoint", response);
+ } catch (TimeoutException e) {
+ // expected that we killed the future when it didn't finish
+ // on it's own in a timely manner
+ }
+ }
+ } finally {
+ //put the original value back
+ if (originalValue == null) {
+ System.clearProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP);
+ } else {
+ System.setProperty(SlingClient.CLIENT_CONNECTION_TIMEOUT_PROP, originalValue);
+ }
+ }
+ }
+
+}