Skip to content

Commit 10f32af

Browse files
ssheikinfindepinineinchnickeddumelendez
authored
Stop container that doesn't match wait strategy (#9474)
Fixes #2877 --------- Co-authored-by: Piotr Findeisen <[email protected]> Co-authored-by: Jan Waś <[email protected]> Co-authored-by: Eddú Meléndez <[email protected]>
1 parent 4aa1b6c commit 10f32af

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

core/src/main/java/org/testcontainers/containers/GenericContainer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ private void tryStart() {
550550
} else {
551551
logger().error("There are no stdout/stderr logs available for the failed container");
552552
}
553+
stop();
553554
}
554555

555556
throw new ContainerLaunchException("Could not create/start container", e);

core/src/test/java/org/testcontainers/containers/GenericContainerTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import com.github.dockerjava.api.DockerClient;
66
import com.github.dockerjava.api.command.InspectContainerResponse;
77
import com.github.dockerjava.api.command.InspectContainerResponse.ContainerState;
8+
import com.github.dockerjava.api.model.Container;
89
import com.github.dockerjava.api.model.ExposedPort;
910
import com.github.dockerjava.api.model.Info;
1011
import com.github.dockerjava.api.model.Ports;
12+
import com.google.common.base.MoreObjects;
13+
import com.google.common.collect.ImmutableList;
1114
import lombok.RequiredArgsConstructor;
1215
import lombok.SneakyThrows;
1316
import lombok.experimental.FieldDefaults;
@@ -28,9 +31,12 @@
2831
import org.testcontainers.utility.DockerImageName;
2932
import org.testcontainers.utility.MountableFile;
3033

34+
import java.time.Duration;
3135
import java.util.Arrays;
36+
import java.util.Collections;
3237
import java.util.List;
3338
import java.util.Map;
39+
import java.util.Optional;
3440
import java.util.concurrent.TimeUnit;
3541
import java.util.function.Predicate;
3642
import java.util.stream.Collectors;
@@ -273,6 +279,63 @@ public void shouldRespectWaitStrategy() {
273279
}
274280
}
275281

282+
@Test
283+
public void testStartupAttemptsDoesNotLeaveContainersRunningWhenWrongWaitStrategyIsUsed() {
284+
try (
285+
GenericContainer<?> container = new GenericContainer<>(TestImages.TINY_IMAGE)
286+
.withLabel("waitstrategy", "wrong")
287+
.withStartupAttempts(3)
288+
.waitingFor(
289+
Wait.forLogMessage("this text does not exist in logs", 1).withStartupTimeout(Duration.ofMillis(1))
290+
)
291+
.withCommand("tail", "-f", "/dev/null");
292+
) {
293+
assertThatThrownBy(container::start).hasStackTraceContaining("Retry limit hit with exception");
294+
}
295+
assertThat(reportLeakedContainers()).isEmpty();
296+
}
297+
298+
private static Optional<String> reportLeakedContainers() {
299+
@SuppressWarnings("resource") // Throws when close is attempted, as this is a global instance.
300+
DockerClient dockerClient = DockerClientFactory.lazyClient();
301+
302+
List<Container> containers = dockerClient
303+
.listContainersCmd()
304+
.withAncestorFilter(Collections.singletonList("alpine:3.17"))
305+
.withLabelFilter(
306+
Arrays.asList(
307+
DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL + "=" + DockerClientFactory.SESSION_ID,
308+
"waitstrategy=wrong"
309+
)
310+
)
311+
// ignore status "exited" - for example, failed containers after using `withStartupAttempts()`
312+
.withStatusFilter(Arrays.asList("created", "restarting", "running", "paused"))
313+
.exec()
314+
.stream()
315+
.collect(ImmutableList.toImmutableList());
316+
317+
if (containers.isEmpty()) {
318+
return Optional.empty();
319+
}
320+
321+
return Optional.of(
322+
String.format(
323+
"Leaked containers: %s",
324+
containers
325+
.stream()
326+
.map(container -> {
327+
return MoreObjects
328+
.toStringHelper("container")
329+
.add("id", container.getId())
330+
.add("image", container.getImage())
331+
.add("imageId", container.getImageId())
332+
.toString();
333+
})
334+
.collect(Collectors.joining(", ", "[", "]"))
335+
)
336+
);
337+
}
338+
276339
static class NoopStartupCheckStrategy extends StartupCheckStrategy {
277340

278341
@Override

0 commit comments

Comments
 (0)