Skip to content

Commit

Permalink
Add logger to HTTP ping checker
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Rishi <ryan@ryanrishi.com>
  • Loading branch information
ryanrishi authored and rohanKanojia committed Jul 28, 2023
1 parent 6a8fffe commit bb612ed
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private List<WaitChecker> prepareWaitCheckers(ImageConfiguration imageConfig, Pr
List<WaitChecker> checkers = new ArrayList<>();

if (wait.getUrl() != null) {
checkers.add(getUrlWaitChecker(imageConfig.getDescription(), projectProperties, wait));
checkers.add(getUrlWaitChecker(imageConfig.getDescription(), projectProperties, wait, log));
}

if (wait.getLog() != null) {
Expand Down Expand Up @@ -138,16 +138,17 @@ private WaitConfiguration getWaitConfiguration(ImageConfiguration imageConfig) {

private WaitChecker getUrlWaitChecker(String imageConfigDesc,
Properties projectProperties,
WaitConfiguration wait) {
WaitConfiguration wait,
Logger log) {
String waitUrl = StrSubstitutor.replace(wait.getUrl(), projectProperties);
WaitConfiguration.HttpConfiguration httpConfig = wait.getHttp();
HttpPingChecker checker;
if (httpConfig != null) {
checker = new HttpPingChecker(waitUrl, httpConfig.getMethod(), httpConfig.getStatus(), httpConfig.isAllowAllHosts());
checker = new HttpPingChecker(waitUrl, httpConfig.getMethod(), httpConfig.getStatus(), httpConfig.isAllowAllHosts(), log);
log.info("%s: Waiting on url %s with method %s for status %s.",
imageConfigDesc, waitUrl, httpConfig.getMethod(), httpConfig.getStatus());
} else {
checker = new HttpPingChecker(waitUrl);
checker = new HttpPingChecker(waitUrl, log);
log.info("%s: Waiting on url %s.", imageConfigDesc, waitUrl);
}
return checker;
Expand Down
16 changes: 11 additions & 5 deletions src/main/java/io/fabric8/maven/docker/wait/HttpPingChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.fabric8.maven.docker.util.Logger;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.RequestBuilder;
Expand All @@ -32,6 +33,7 @@ public class HttpPingChecker implements WaitChecker {
private String url;
private String method;
private boolean allowAllHosts;
private final Logger log;

// Disable HTTP client retries by default.
private static final int HTTP_CLIENT_RETRIES = 0;
Expand All @@ -46,9 +48,10 @@ public class HttpPingChecker implements WaitChecker {
* @param method HTTP method to use
* @param status status code to check
*/
public HttpPingChecker(String url, String method, String status) {
public HttpPingChecker(String url, String method, String status, Logger log) {
this.url = url;
this.method = method;
this.log = log;

Matcher matcher = Pattern.compile("^(\\d+)\\s*\\.\\.+\\s*(\\d+)$").matcher(status);
if (matcher.matches()) {
Expand All @@ -59,12 +62,12 @@ public HttpPingChecker(String url, String method, String status) {
}
}

public HttpPingChecker(String waitUrl) {
this(waitUrl, WaitConfiguration.DEFAULT_HTTP_METHOD, WaitConfiguration.DEFAULT_STATUS_RANGE);
public HttpPingChecker(String waitUrl, final Logger log) {
this(waitUrl, WaitConfiguration.DEFAULT_HTTP_METHOD, WaitConfiguration.DEFAULT_STATUS_RANGE, log);
}

public HttpPingChecker(String url, String method, String status, boolean allowAllHosts) {
this(url, method, status);
public HttpPingChecker(String url, String method, String status, boolean allowAllHosts, final Logger log) {
this(url, method, status, log);
this.allowAllHosts = allowAllHosts;
}

Expand All @@ -74,6 +77,7 @@ public boolean check() {
return ping();
} catch (IOException exception) {
// Could occur and then the check is always considered as failed
log.debug("Check failed due to %s: %s", exception.getMessage(), exception);
return false;
}
}
Expand Down Expand Up @@ -109,11 +113,13 @@ private boolean ping() throws IOException {
.build();
}

log.debug("Checking %s %s", method.toUpperCase(), url);
try (CloseableHttpResponse response = httpClient.execute(RequestBuilder.create(method.toUpperCase()).setUri(url).build())) {
int responseCode = response.getStatusLine().getStatusCode();
if (responseCode == HttpURLConnection.HTTP_NOT_IMPLEMENTED) {
throw new IllegalArgumentException("Invalid or not supported HTTP method '" + method.toUpperCase() + "' for checking " + url);
}
log.debug("%s %s returned %s",method.toUpperCase(), url, responseCode);
return responseCode >= statusMin && responseCode <= statusMax;
} finally {
httpClient.close();
Expand Down
19 changes: 11 additions & 8 deletions src/test/java/io/fabric8/maven/docker/util/WaitUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;

import static org.mockito.Mockito.mock;

/**
* @author roland
* @since 18.10.14
Expand All @@ -33,11 +35,12 @@ class WaitUtilTest {
static int port;
static String httpPingUrl;
private static String serverMethodToAssert;
private final static Logger logger = mock(Logger.class);

@Test
void httpFail() {

HttpPingChecker checker = new HttpPingChecker("http://127.0.0.1:" + port + "/fake-context/");
HttpPingChecker checker = new HttpPingChecker("http://127.0.0.1:" + port + "/fake-context/", logger);
Assertions.assertThrows(TimeoutException.class, ()-> wait(500, checker));
}

Expand All @@ -51,43 +54,43 @@ private static long wait(int failAfter, int wait, WaitChecker checker) throws Wa

@Test
void httpSuccess() throws TimeoutException, PreconditionFailedException {
HttpPingChecker checker = new HttpPingChecker(httpPingUrl);
HttpPingChecker checker = new HttpPingChecker(httpPingUrl, logger);
long waited = wait(700, checker);
Assertions.assertTrue( waited < 700,"Waited less than 700ms: " + waited);
}

@Test
void containerNotRunningButWaitConditionOk() throws TimeoutException, PreconditionFailedException {
HttpPingChecker checker = new HttpPingChecker(httpPingUrl);
HttpPingChecker checker = new HttpPingChecker(httpPingUrl, logger);
long waited = wait(1,700, checker);
Assertions.assertTrue( waited < 700,"Waited less than 700ms: " + waited);
}

@Test
void containerNotRunningAndWaitConditionNok() {
HttpPingChecker checker = new HttpPingChecker("http://127.0.0.1:" + port + "/fake-context/");
HttpPingChecker checker = new HttpPingChecker("http://127.0.0.1:" + port + "/fake-context/", logger);
Assertions.assertThrows(PreconditionFailedException.class, ()-> wait(0, 700, checker));
}

@Test
void httpSuccessWithStatus() throws TimeoutException, PreconditionFailedException {
for (String status : new String[] { "200", "200 ... 300", "200..250" }) {
long waited = wait(700, new HttpPingChecker(httpPingUrl, WaitConfiguration.DEFAULT_HTTP_METHOD, status));
long waited = wait(700, new HttpPingChecker(httpPingUrl, WaitConfiguration.DEFAULT_HTTP_METHOD, status, logger));
Assertions.assertTrue( waited < 700,"Waited less than 700ms: " + waited);
}
}

@Test
void httpFailWithStatus() {
HttpPingChecker checker = new HttpPingChecker(httpPingUrl, WaitConfiguration.DEFAULT_HTTP_METHOD, "500");
HttpPingChecker checker = new HttpPingChecker(httpPingUrl, WaitConfiguration.DEFAULT_HTTP_METHOD, "500", logger);
Assertions.assertThrows(TimeoutException.class, ()->wait(700, checker));
}

@Test
void httpSuccessWithGetMethod() throws Exception {
serverMethodToAssert = "GET";
try {
HttpPingChecker checker = new HttpPingChecker(httpPingUrl, "GET", WaitConfiguration.DEFAULT_STATUS_RANGE);
HttpPingChecker checker = new HttpPingChecker(httpPingUrl, "GET", WaitConfiguration.DEFAULT_STATUS_RANGE, logger);
long waited = wait(700, checker);
Assertions.assertTrue( waited < 700,"Waited less than 500ms: " + waited);
} finally {
Expand Down Expand Up @@ -191,7 +194,7 @@ public static void createServer() throws IOException {

// preload - first time use almost always lasts much longer (i'm assuming its http client initialization behavior)
try {
wait(700, new HttpPingChecker(httpPingUrl));
wait(700, new HttpPingChecker(httpPingUrl, logger));
} catch (TimeoutException | PreconditionFailedException exp) {
// expected
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package io.fabric8.maven.docker.wait;

import java.io.IOException;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_SELF;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import io.fabric8.maven.docker.util.Logger;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class HttpPingCheckerTest {
@Mock
private Logger logger;

private HttpPingChecker httpPingChecker;

@BeforeEach
void setup() {
httpPingChecker = new HttpPingChecker("https://example.com", logger);
}

@Test
void checkingAfterSuccessfulResponseSucceeds() throws IOException {
try (MockedStatic<HttpClientBuilder> mockedStatic = mockStatic(HttpClientBuilder.class)) {
final CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
final HttpClientBuilder httpClientBuilder = mock(HttpClientBuilder.class, RETURNS_SELF);
when(httpClientBuilder.build()).thenReturn(httpClient);
mockedStatic.when(HttpClientBuilder::create).thenReturn(httpClientBuilder);

final CloseableHttpResponse response = mock(CloseableHttpResponse.class);
when(httpClient.execute(any())).thenReturn(response);

final StatusLine statusLine = mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(200);
when(response.getStatusLine()).thenReturn(statusLine);

assertTrue(httpPingChecker.check());
}
}

@Test
void checkingAfterUnsuccessfulResponseFails() throws IOException {
try (MockedStatic<HttpClientBuilder> mockedStatic = mockStatic(HttpClientBuilder.class)) {
final CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
final HttpClientBuilder httpClientBuilder = mock(HttpClientBuilder.class, RETURNS_SELF);
when(httpClientBuilder.build()).thenReturn(httpClient);
mockedStatic.when(HttpClientBuilder::create).thenReturn(httpClientBuilder);

final CloseableHttpResponse response = mock(CloseableHttpResponse.class);
when(httpClient.execute(any())).thenReturn(response);

final StatusLine statusLine = mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(500);
when(response.getStatusLine()).thenReturn(statusLine);

assertFalse(httpPingChecker.check());
}
}

@Test
void checkingAfterIOExceptionFails() throws IOException {
try (MockedStatic<HttpClientBuilder> mockedStatic = mockStatic(HttpClientBuilder.class)) {
final CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
final HttpClientBuilder httpClientBuilder = mock(HttpClientBuilder.class, RETURNS_SELF);
when(httpClientBuilder.build()).thenReturn(httpClient);
mockedStatic.when(HttpClientBuilder::create).thenReturn(httpClientBuilder);

final IOException ioException = mock(IOException.class);
final String message = "Error " + UUID.randomUUID();
when(ioException.getMessage()).thenReturn(message);
when(httpClient.execute(any())).thenThrow(ioException);

assertFalse(httpPingChecker.check());
verify(logger).debug(any(), eq(message), any());
}
}
}

0 comments on commit bb612ed

Please sign in to comment.