Skip to content

Instantly share code, notes, and snippets.

@petrbouda
Created March 16, 2021 07:59
Show Gist options
  • Save petrbouda/b72dbc9692d7d8e396ca19fdb17b73fd to your computer and use it in GitHub Desktop.
Save petrbouda/b72dbc9692d7d8e396ca19fdb17b73fd to your computer and use it in GitHub Desktop.
Assert Logging in JUNIT Tests
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import org.junit.jupiter.api.Assertions;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
public class AssertAppender extends AppenderBase<ILoggingEvent> implements AutoCloseable {
private final Logger logger;
private final Predicate<ILoggingEvent> predicate;
private final CountDownLatch latch = new CountDownLatch(1);
public AssertAppender(Class<?> clazz, Predicate<ILoggingEvent> predicate) {
this.logger = (Logger) LoggerFactory.getLogger(clazz);
this.logger.setLevel(Level.INFO);
this.predicate = predicate;
setContext((LoggerContext) LoggerFactory.getILoggerFactory());
}
@Override
protected void append(ILoggingEvent log) {
if (predicate.test(log)) {
latch.countDown();
}
}
@Override
public void start() {
logger.addAppender(this);
super.start();
}
public void waitForAssertion(Duration duration) throws InterruptedException {
boolean countdownResult = latch.await(duration.toMillis(), TimeUnit.MILLISECONDS);
if (!countdownResult) {
Assertions.fail("AssertAppender failed in tracing logs");
}
}
@Override
public void close() {
logger.detachAppender(this);
}
}
@Test
public void attemptsExceededOnIOException() throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("http://non-existing"))
.build();
Predicate<ILoggingEvent> assertion = event ->
event.toString().startsWith("[WARN] Retrying: attempt=3");
try (var appender = new AssertAppender(HttpInvocation.class, assertion)) {
appender.start();
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(10))
.build();
Executable executable =
() -> HttpInvocation.builder(request, HttpResponse.BodyHandlers.ofString())
.withHttpClient(httpClient)
.withMaxAttempts(3)
.withRetryDelay(Duration.ofMillis(100))
.withThrowWhenRetryOnResponseExceeded(false)
.build()
.invoke()
.get(1, TimeUnit.SECONDS);
ExecutionException ex = assertThrows(ExecutionException.class, executable);
appender.waitForAssertion(Duration.ofSeconds(1));
assertEquals(ConnectException.class, ex.getCause().getClass());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment