From 3d3f1047b4ee696c119d5267c68ffbdeb0e7388f Mon Sep 17 00:00:00 2001 From: Richard North Date: Thu, 22 Sep 2016 10:27:28 +0100 Subject: [PATCH] Serialize all Docker Compose operations, to avoid concurrency issues when running tests in parallel (Docker Compose exhibits race conditions under concurrent usage - HT to @pcornish) --- .../containers/DockerComposeContainer.java | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index b01aaa70b79..2ee483dd2bc 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -47,6 +47,8 @@ public class DockerComposeContainer> e private Map scalingPreferences = new HashMap<>(); private DockerClient dockerClient; + private static final Object MUTEX = new Object(); + /** * Properties that should be passed through to all Compose and ambassador containers (not * necessarily to containers that are spawned by Compose itself) @@ -79,12 +81,13 @@ public void starting(Description description) { profiler.setLogger(logger()); profiler.start("Docker compose container startup"); - pullImages(); - applyScaling(); // scale before up, so that all scaled instances are available first for linking - createServices(); - registerContainersForShutdown(); - startAmbassadorContainers(profiler); - + synchronized (MUTEX) { + pullImages(); + applyScaling(); // scale before up, so that all scaled instances are available first for linking + createServices(); + registerContainersForShutdown(); + startAmbassadorContainers(profiler); + } } private void pullImages() { @@ -184,19 +187,22 @@ private Logger logger() { @Override @VisibleForTesting public void finished(Description description) { - // shut down all the ambassador containers - ambassadorContainers.forEach((String address, AmbassadorContainer container) -> container.stop()); - // Kill the services using docker-compose - getDockerCompose("down -v") - .start(); + synchronized (MUTEX) { + // 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 services using docker-compose + getDockerCompose("down -v") + .start(); + + // 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(); + // kill the spawned service containers + spawnedContainerIds.forEach(id -> ResourceReaper.instance().stopAndRemoveContainer(id)); + spawnedContainerIds.clear(); + } } public SELF withExposedService(String serviceName, int servicePort) {