Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import lombok.NonNull;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.Synchronized;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -169,7 +170,7 @@ public class GenericContainer<SELF extends GenericContainer<SELF>>
*/
@Setter(AccessLevel.NONE)
@VisibleForTesting
String containerId;
volatile String containerId;

@Setter(AccessLevel.NONE)
private InspectContainerResponse containerInfo;
Expand Down Expand Up @@ -306,6 +307,7 @@ public String getContainerId() {
* Starts the container using docker, pulling an image if necessary.
*/
@Override
@Synchronized
@SneakyThrows({ InterruptedException.class, ExecutionException.class })
public void start() {
if (containerId != null) {
Expand Down Expand Up @@ -634,6 +636,7 @@ private void connectToPortForwardingNetwork(String networkMode) {
* Kill and remove the container.
*/
@Override
@Synchronized
public void stop() {
if (containerId == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.testcontainers.clickhouse;

import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.Synchronized;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;

/**
Expand All @@ -24,11 +25,13 @@ public static ConnectionFactoryOptions getOptions(ClickHouseContainer container)
}

@Override
@Synchronized
public void start() {
this.container.start();
}

@Override
@Synchronized
public void stop() {
this.container.stop();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.testcontainers.junit.jupiter;

import org.junit.jupiter.api.Test;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.lifecycle.Startables;
import org.testcontainers.utility.DockerImageName;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Verifies that concurrent {@link GenericContainer#start()} calls on the same
* container do not result in {@link GenericContainer#doStart()} being
* called more than once.
*
* <p>A background thread calls {@code container.start()} during class initialization,
* racing with the extension's {@link Startables#deepStart(Stream)} which also starts
* the container as part of the {@code @Container} lifecycle.</p>
*/
@Testcontainers(parallel = true)
class ParallelDependsOnTest {
static {
// Pre-initialize the Docker client to increase the chance of a race
// and to emulate a test suite where an earlier test class already
// triggered the initialization.
DockerClientFactory.instance().client();
}

private static final AtomicInteger doStartCount = new AtomicInteger();

@Container
private static final StartCountingContainer container = new StartCountingContainer(
JUnitJupiterTestImages.HTTPD_IMAGE,
doStartCount
);

static {
// Race with the extension's Startables.deepStart.
new Thread(() -> container.start()).start();
}

@Test
void containerShouldBeStartedOnlyOnce() {
assertThat(container.isRunning()).isTrue();
assertThat(doStartCount).as("doStart() invocations").hasValue(1);
}

private static class StartCountingContainer extends GenericContainer<StartCountingContainer> {

private final AtomicInteger doStartCount;

StartCountingContainer(DockerImageName image, AtomicInteger doStartCount) {
super(image);
this.doStartCount = doStartCount;
}

@Override
protected void doStart() {
doStartCount.incrementAndGet();
super.doStart();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.testcontainers.mariadb;

import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.Synchronized;
import org.mariadb.r2dbc.MariadbConnectionFactoryProvider;
import org.testcontainers.lifecycle.Startable;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;
Expand Down Expand Up @@ -42,11 +43,13 @@ public Set<Startable> getDependencies() {
}

@Override
@Synchronized
public void start() {
this.container.start();
}

@Override
@Synchronized
public void stop() {
this.container.stop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.r2dbc.mssql.MssqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.Synchronized;
import org.testcontainers.lifecycle.Startable;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;

Expand Down Expand Up @@ -43,11 +44,13 @@ public Set<Startable> getDependencies() {
}

@Override
@Synchronized
public void start() {
this.container.start();
}

@Override
@Synchronized
public void stop() {
this.container.stop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.asyncer.r2dbc.mysql.MySqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.Synchronized;
import org.testcontainers.lifecycle.Startable;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;

Expand Down Expand Up @@ -42,11 +43,13 @@ public Set<Startable> getDependencies() {
}

@Override
@Synchronized
public void start() {
this.container.start();
}

@Override
@Synchronized
public void stop() {
this.container.stop();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.testcontainers.oracle;

import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.Synchronized;
import org.testcontainers.lifecycle.Startable;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;

Expand Down Expand Up @@ -41,11 +42,13 @@ public Set<Startable> getDependencies() {
}

@Override
@Synchronized
public void start() {
this.container.start();
}

@Override
@Synchronized
public void stop() {
this.container.stop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.Synchronized;
import org.testcontainers.lifecycle.Startable;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;

Expand Down Expand Up @@ -42,11 +43,13 @@ public Set<Startable> getDependencies() {
}

@Override
@Synchronized
public void start() {
this.container.start();
}

@Override
@Synchronized
public void stop() {
this.container.stop();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Volume;
import com.google.common.collect.ImmutableSet;
import lombok.Synchronized;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -351,6 +352,7 @@ public void afterTest(TestDescription description, Optional<Throwable> throwable
}

@Override
@Synchronized
public void stop() {
if (driver != null) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Volume;
import com.google.common.collect.ImmutableSet;
import lombok.Synchronized;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -202,6 +203,7 @@ public void afterTest(TestDescription description, Optional<Throwable> throwable
}

@Override
@Synchronized
public void stop() {
if (vncRecordingContainer != null) {
try {
Expand Down