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 @@ -169,7 +169,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 @@ -307,7 +307,7 @@ public String getContainerId() {
*/
@Override
@SneakyThrows({ InterruptedException.class, ExecutionException.class })
public void start() {
public synchronized void start() {
if (containerId != null) {
return;
}
Expand Down Expand Up @@ -634,7 +634,7 @@ private void connectToPortForwardingNetwork(String networkMode) {
* Kill and remove the container.
*/
@Override
public void stop() {
public synchronized void stop() {
if (containerId == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public static ConnectionFactoryOptions getOptions(ClickHouseContainer container)
}

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

@Override
public void stop() {
public synchronized 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
Expand Up @@ -42,12 +42,12 @@ public Set<Startable> getDependencies() {
}

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

@Override
public void stop() {
public synchronized void stop() {
this.container.stop();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public Set<Startable> getDependencies() {
}

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

@Override
public void stop() {
public synchronized void stop() {
this.container.stop();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ public Set<Startable> getDependencies() {
}

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

@Override
public void stop() {
public synchronized void stop() {
this.container.stop();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ public Set<Startable> getDependencies() {
}

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

@Override
public void stop() {
public synchronized void stop() {
this.container.stop();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ public Set<Startable> getDependencies() {
}

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

@Override
public void stop() {
public synchronized void stop() {
this.container.stop();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ public void afterTest(TestDescription description, Optional<Throwable> throwable
}

@Override
public void stop() {
public synchronized void stop() {
if (driver != null) {
try {
driver.quit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public void afterTest(TestDescription description, Optional<Throwable> throwable
}

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