Skip to content

Commit 0035c31

Browse files
authored
Avoid connection leaks in LogUtils (#2834)
1 parent ddae79c commit 0035c31

File tree

2 files changed

+44
-19
lines changed

2 files changed

+44
-19
lines changed

core/src/main/java/org/testcontainers/containers/wait/strategy/LogMessageWaitStrategy.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,53 @@
11
package org.testcontainers.containers.wait.strategy;
22

3+
import com.github.dockerjava.api.command.LogContainerCmd;
4+
import lombok.SneakyThrows;
35
import org.testcontainers.DockerClientFactory;
46
import org.testcontainers.containers.ContainerLaunchException;
7+
import org.testcontainers.containers.output.FrameConsumerResultCallback;
58
import org.testcontainers.containers.output.OutputFrame;
69
import org.testcontainers.containers.output.WaitingConsumer;
7-
import org.testcontainers.utility.LogUtils;
810

11+
import java.io.IOException;
912
import java.util.concurrent.TimeUnit;
1013
import java.util.concurrent.TimeoutException;
1114
import java.util.function.Predicate;
1215

16+
import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR;
17+
import static org.testcontainers.containers.output.OutputFrame.OutputType.STDOUT;
18+
1319
public class LogMessageWaitStrategy extends AbstractWaitStrategy {
1420

1521
private String regEx;
1622

1723
private int times = 1;
1824

1925
@Override
26+
@SneakyThrows(IOException.class)
2027
protected void waitUntilReady() {
2128
WaitingConsumer waitingConsumer = new WaitingConsumer();
22-
LogUtils.followOutput(DockerClientFactory.instance().client(), waitStrategyTarget.getContainerId(), waitingConsumer);
2329

24-
Predicate<OutputFrame> waitPredicate = outputFrame ->
25-
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
26-
outputFrame.getUtf8String().matches("(?s)" + regEx);
30+
LogContainerCmd cmd = DockerClientFactory.instance().client().logContainerCmd(waitStrategyTarget.getContainerId())
31+
.withFollowStream(true)
32+
.withSince(0)
33+
.withStdOut(true)
34+
.withStdErr(true);
35+
36+
try (FrameConsumerResultCallback callback = new FrameConsumerResultCallback()) {
37+
callback.addConsumer(STDOUT, waitingConsumer);
38+
callback.addConsumer(STDERR, waitingConsumer);
39+
40+
cmd.exec(callback);
41+
42+
Predicate<OutputFrame> waitPredicate = outputFrame ->
43+
// (?s) enables line terminator matching (equivalent to Pattern.DOTALL)
44+
outputFrame.getUtf8String().matches("(?s)" + regEx);
2745

28-
try {
29-
waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, times);
30-
} catch (TimeoutException e) {
31-
throw new ContainerLaunchException("Timed out waiting for log output matching '" + regEx + "'");
46+
try {
47+
waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, times);
48+
} catch (TimeoutException e) {
49+
throw new ContainerLaunchException("Timed out waiting for log output matching '" + regEx + "'");
50+
}
3251
}
3352
}
3453

core/src/main/java/org/testcontainers/utility/LogUtils.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import com.github.dockerjava.api.DockerClient;
44
import com.github.dockerjava.api.command.LogContainerCmd;
5+
import lombok.SneakyThrows;
56
import lombok.experimental.UtilityClass;
67
import org.testcontainers.containers.output.FrameConsumerResultCallback;
78
import org.testcontainers.containers.output.OutputFrame;
89
import org.testcontainers.containers.output.ToStringConsumer;
910
import org.testcontainers.containers.output.WaitingConsumer;
1011

12+
import java.io.Closeable;
13+
import java.io.IOException;
1114
import java.util.function.Consumer;
1215

1316
import static org.testcontainers.containers.output.OutputFrame.OutputType.STDERR;
@@ -59,6 +62,7 @@ public void followOutput(DockerClient dockerClient,
5962
* @param types types of {@link OutputFrame} to receive
6063
* @return all previous output frames (stdout/stderr being separated by newline characters)
6164
*/
65+
@SneakyThrows(IOException.class)
6266
public String getOutput(DockerClient dockerClient,
6367
String containerId,
6468
OutputFrame.OutputType... types) {
@@ -73,17 +77,19 @@ public String getOutput(DockerClient dockerClient,
7377

7478
final ToStringConsumer consumer = new ToStringConsumer();
7579
final WaitingConsumer wait = new WaitingConsumer();
76-
attachConsumer(dockerClient, containerId, consumer.andThen(wait), false, types);
77-
78-
wait.waitUntilEnd();
79-
return consumer.toUtf8String();
80+
try (Closeable closeable = attachConsumer(dockerClient, containerId, consumer.andThen(wait), false, types)) {
81+
wait.waitUntilEnd();
82+
return consumer.toUtf8String();
83+
}
8084
}
8185

82-
private static void attachConsumer(DockerClient dockerClient,
83-
String containerId,
84-
Consumer<OutputFrame> consumer,
85-
boolean followStream,
86-
OutputFrame.OutputType... types) {
86+
private static Closeable attachConsumer(
87+
DockerClient dockerClient,
88+
String containerId,
89+
Consumer<OutputFrame> consumer,
90+
boolean followStream,
91+
OutputFrame.OutputType... types
92+
) {
8793

8894
final LogContainerCmd cmd = dockerClient.logContainerCmd(containerId)
8995
.withFollowStream(followStream)
@@ -96,6 +102,6 @@ private static void attachConsumer(DockerClient dockerClient,
96102
if (type == STDERR) cmd.withStdErr(true);
97103
}
98104

99-
cmd.exec(callback);
105+
return cmd.exec(callback);
100106
}
101107
}

0 commit comments

Comments
 (0)