From 695212232d4d0920cc39b09eaf5bbcf24dbb8de8 Mon Sep 17 00:00:00 2001 From: Valdis Rigdon Date: Mon, 22 Aug 2016 13:33:40 -0400 Subject: [PATCH] Reap docker-compose networks earlier For docker-compose instances with custom networks, these need to be reaped after each test as they could potentially define overlapping subnets. --- .../containers/DockerComposeContainer.java | 11 ++++++- .../utility/ResourceReaper.java | 11 ++++++- .../junit/BaseDockerComposeTest.java | 30 +++++++++++++++++-- .../junit/DockerComposeV2WithNetworkTest.java | 21 +++++++++++++ .../v2-compose-test-with-network.yml | 9 ++++++ 5 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java create mode 100644 core/src/test/resources/v2-compose-test-with-network.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 1362a07ad87..10b2df9c0c3 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -130,6 +130,12 @@ private void registerContainersForShutdown() { // Ensure that the default network for this compose environment, if any, is also cleaned up ResourceReaper.instance().registerNetworkForCleanup(identifier + "_default"); + // Compose can define their own networks as well; ensure these are cleaned up + dockerClient.listNetworksCmd().exec().forEach(network -> { + if (network.getName().contains(identifier)) { + ResourceReaper.instance().registerNetworkForCleanup(network.getName()); + } + }); // remember the IDs to allow containers to be killed as soon as we reach stop() spawnedContainerIds = containers.stream() @@ -185,6 +191,9 @@ public void finished(Description description) { // shut down all the ambassador containers ambassadorContainers.forEach((String address, AmbassadorContainer container) -> container.stop()); + // remove the networks before removing the containers + ResourceReaper.instance().removeNetworks(identifier); + // kill the spawned service containers spawnedContainerIds.forEach(id -> ResourceReaper.instance().stopAndRemoveContainer(id)); spawnedContainerIds.clear(); @@ -305,4 +314,4 @@ public void start() { } logger().info("Docker compose has finished running"); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java index e8df7179bdb..754cb6e74a6 100644 --- a/core/src/main/java/org/testcontainers/utility/ResourceReaper.java +++ b/core/src/main/java/org/testcontainers/utility/ResourceReaper.java @@ -121,6 +121,14 @@ public void registerNetworkForCleanup(String networkName) { registeredNetworks.add(networkName); } + /** + * Removes any networks that contain the identifier. + * @param identifier + */ + public void removeNetworks(String identifier) { + removeNetwork(identifier); + } + private void removeNetwork(String networkName) { List networks; try { @@ -133,10 +141,11 @@ private void removeNetwork(String networkName) { for (Network network : networks) { try { dockerClient.removeNetworkCmd(network.getId()).exec(); + registeredNetworks.remove(network.getId()); LOGGER.debug("Removed network: {}", networkName); } catch (DockerException e) { LOGGER.trace("Error encountered removing network (name: {}) - it may not have been removed", network.getName()); } } } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java b/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java index 09af26e9afe..8024eac22a4 100644 --- a/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java +++ b/core/src/test/java/org/testcontainers/junit/BaseDockerComposeTest.java @@ -1,18 +1,23 @@ package org.testcontainers.junit; +import com.github.dockerjava.api.model.Network; import org.jetbrains.annotations.NotNull; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.*; import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.utility.TestEnvironment; import redis.clients.jedis.Jedis; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import static org.hamcrest.CoreMatchers.is; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; +import static org.rnorth.visibleassertions.VisibleAssertions.assertThat; /** * Created by rnorth on 21/05/2016. @@ -23,6 +28,8 @@ public abstract class BaseDockerComposeTest { protected abstract DockerComposeContainer getEnvironment(); + private List existingNetworks = new ArrayList<>(); + @BeforeClass public static void checkVersion() { Assume.assumeTrue(TestEnvironment.dockerApiAtLeast("1.22")); @@ -59,6 +66,23 @@ public void secondTest() { // However, @Rule creates a separate DockerComposeContainer instance per test, so this just shouldn't happen } + @Before + public void captureNetworks() { + existingNetworks.addAll(findAllNetworks()); + } + + @After + public void verifyNoNetworks() { + assertThat("The networks", findAllNetworks(), is(existingNetworks)); + } + + private List findAllNetworks() { + return DockerClientFactory.instance().client().listNetworksCmd().exec().stream() + .map(Network::getName) + .sorted() + .collect(Collectors.toList()); + } + @NotNull private Callable getLivenessCheck(Jedis jedis) { return () -> { diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java new file mode 100644 index 00000000000..26764476687 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeV2WithNetworkTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.junit; + +import java.io.File; + +import org.junit.Rule; +import org.testcontainers.containers.DockerComposeContainer; + +public class DockerComposeV2WithNetworkTest extends BaseDockerComposeTest { + + @Rule + public DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/v2-compose-test-with-network.yml")) + .withExposedService("redis_1", REDIS_PORT); + + @Override + protected DockerComposeContainer getEnvironment() { + return environment; + } + + + +} diff --git a/core/src/test/resources/v2-compose-test-with-network.yml b/core/src/test/resources/v2-compose-test-with-network.yml new file mode 100644 index 00000000000..82b54a85823 --- /dev/null +++ b/core/src/test/resources/v2-compose-test-with-network.yml @@ -0,0 +1,9 @@ +version: '2' +services: + redis: + image: redis + networks: + - redis-net + +networks: + redis-net: