Skip to content

Commit

Permalink
Extend from an AbstractLogMessageWaitStrategy
Browse files Browse the repository at this point in the history
  • Loading branch information
TomCools committed Jul 17, 2023
1 parent 69a2da0 commit bdd1aed
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.testcontainers.containers.output.FrameConsumerResultCallback;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.output.WaitingConsumer;
import org.testcontainers.containers.wait.strategy.AbstractLogMessageWaitStrategy;
import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy;

import java.io.IOException;
Expand All @@ -15,6 +16,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/*
This wait strategy has following characteristics
Expand All @@ -24,48 +26,28 @@
*/

@Slf4j
public class MultiLogMessageWaitStrategy extends AbstractWaitStrategy {

private static final int CHECK_TIMES = 1;
public class MultiLogMessageWaitStrategy extends AbstractLogMessageWaitStrategy {

private LinkedBlockingDeque<String> regEx;

@Override
@SneakyThrows(IOException.class)
protected void waitUntilReady() {
WaitingConsumer waitingConsumer = new WaitingConsumer();

LogContainerCmd cmd = waitStrategyTarget
.getDockerClient()
.logContainerCmd(waitStrategyTarget.getContainerId())
.withFollowStream(true)
.withSince(0)
.withStdOut(true)
.withStdErr(true);

try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) {
callback.addConsumer(OutputFrame.OutputType.STDOUT, waitingConsumer);
callback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer);

cmd.exec(callback);

Predicate<OutputFrame> waitPredicate = outputFrame -> {
String nextExpectedRegex = regEx.peek();
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
if(outputFrame.getUtf8String().matches("(?s)" + nextExpectedRegex)) {
// remove the matched item from the collection.
regEx.pop();
log.info("Regex {} encountered. Waiting for {} more regex statements.", nextExpectedRegex, regEx.size());
}
// If collection is now empty, we are finished.
return regEx.isEmpty();
};
try {
waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, CHECK_TIMES);
} catch (TimeoutException e) {
throw new ContainerLaunchException("Timed out waiting for log output matching '" + regEx + "'");
protected Predicate<OutputFrame> waitPredicate() {
return outputFrame -> {
String nextExpectedRegex = regEx.peek();
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
if(outputFrame.getUtf8String().matches("(?s)" + nextExpectedRegex)) {
// remove the matched item from the collection.
regEx.pop();
log.info("Regex {} encountered. Waiting for {} more regex statements.", nextExpectedRegex, regEx.size());
}
}
// If collection is now empty, we are finished.
return regEx.isEmpty();
};
}

@Override
protected String timeoutErrorMessage() {
return "Timed out waiting for log output. Still expecting following log lines: '" + String.join(",", regEx) + "'";
}

public MultiLogMessageWaitStrategy withRegex(String... regEx) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.testcontainers.containers.wait.strategy;

import com.github.dockerjava.api.command.LogContainerCmd;
import lombok.SneakyThrows;
import org.testcontainers.containers.ContainerLaunchException;
import org.testcontainers.containers.output.FrameConsumerResultCallback;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.output.WaitingConsumer;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;

public abstract class AbstractLogMessageWaitStrategy extends AbstractWaitStrategy {

protected int times = 1;

@Override
@SneakyThrows(IOException.class)
protected void waitUntilReady() {
WaitingConsumer waitingConsumer = new WaitingConsumer();

LogContainerCmd cmd = waitStrategyTarget
.getDockerClient()
.logContainerCmd(waitStrategyTarget.getContainerId())
.withFollowStream(true)
.withSince(0)
.withStdOut(true)
.withStdErr(true);

try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) {
callback.addConsumer(OutputFrame.OutputType.STDOUT, waitingConsumer);
callback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer);

cmd.exec(callback);

try {
waitingConsumer.waitUntil(waitPredicate(), startupTimeout.getSeconds(), TimeUnit.SECONDS, times);
} catch (TimeoutException e) {
throw new ContainerLaunchException(timeoutErrorMessage());
}
}
}

protected abstract Predicate<OutputFrame> waitPredicate();
protected abstract String timeoutErrorMessage();

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,21 @@
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;

public class LogMessageWaitStrategy extends AbstractWaitStrategy {
public class LogMessageWaitStrategy extends AbstractLogMessageWaitStrategy {

private String regEx;

private int times = 1;
@Override
protected Predicate<OutputFrame> waitPredicate() {
return outputFrame -> {
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
return outputFrame.getUtf8String().matches("(?s)" + regEx);
};
}

@Override
@SneakyThrows(IOException.class)
protected void waitUntilReady() {
WaitingConsumer waitingConsumer = new WaitingConsumer();

LogContainerCmd cmd = waitStrategyTarget
.getDockerClient()
.logContainerCmd(waitStrategyTarget.getContainerId())
.withFollowStream(true)
.withSince(0)
.withStdOut(true)
.withStdErr(true);

try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) {
callback.addConsumer(OutputFrame.OutputType.STDOUT, waitingConsumer);
callback.addConsumer(OutputFrame.OutputType.STDERR, waitingConsumer);

cmd.exec(callback);

Predicate<OutputFrame> waitPredicate = outputFrame -> {
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
return outputFrame.getUtf8String().matches("(?s)" + regEx);
};
try {
waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, times);
} catch (TimeoutException e) {
throw new ContainerLaunchException("Timed out waiting for log output matching '" + regEx + "'");
}
}
protected String timeoutErrorMessage() {
return "Timed out waiting for log output matching '" + regEx + "'";
}

public LogMessageWaitStrategy withRegEx(String regEx) {
Expand Down

0 comments on commit bdd1aed

Please sign in to comment.