ContainerConnectionDetailsFactory.getContainer() is doing
if (this.container instanceof Startable startable) {
startable.start();
}
While TestcontainersLifecycleBeanPostProcessor.initializeStartables(...) already started the MockServer
Comment From: philwebb
Is this causing an issue? Can you provide a sample application showing the actual problem you're facing?
Comment From: marcantoine-bibeau
I do not think it creates a big problem but still created a regression on my side because I'm wrapping the MockServer and override the start() method to perform additional stuff. I can fix by verifying if the TestContainer is running but would be ideal to not start twice?
Comment From: snicoll
Can you please share the sample we've requested? See also https://github.com/spring-projects/spring-boot/wiki/How-To-Get-Help
Comment From: wilkinsona
We could perhaps use a non-null response from ContainerState#getContainerId() to determine that a container's already been started (as ContainerState#getMappedPort(int) does) but that won't work for every Startable implementation. Given this, it appears to be impossible for us to tell with 100% certainty if a container's already been started. @marcantoine-bibeau, I'd encourage you to implement start() such that it is idempotent as it is in GenericContainer.
Comment From: nosan
@wilkinsona Is it possible to add the following condition?
protected final C getContainer() {
Assert.state(this.container != null,
"Container cannot be obtained before the connection details bean has been initialized");
if (!this.container.isRunning() && this.container instanceof Startable startable) {
startable.start();
}
return this.container;
}
org.testcontainers.containers.ContainerState contains the following default methods:
/**
* @return is the container currently running?
*/
default boolean isRunning() {
if (getContainerId() == null) {
return false;
}
try {
Boolean running = getCurrentContainerInfo().getState().getRunning();
return Boolean.TRUE.equals(running);
} catch (DockerException e) {
return false;
}
}
/**
* @return is the container created?
*/
default boolean isCreated() {
if (getContainerId() == null) {
return false;
}
try {
String status = getCurrentContainerInfo().getState().getStatus();
return "created".equalsIgnoreCase(status) || isRunning();
} catch (DockerException e) {
return false;
}
}
Comment From: wilkinsona
Yes, that's what I was (poorly) describing above when talking about the container ID. It'll certainly help, but I'm not sure that it'll address the problem 100% of the time as there appears to be an implied assumption in Testcontainers that start() will be idempotent. If you've only got a Startable and start() isn't idempotent, I think it's possible that something will be started twice either by Boot or by a combination of Boot and Testcontainers.
Comment From: marcantoine-bibeau
That I was not aware, I thought that start() would only be called once. I'll definitely do that on my side! Feel free to improve on Spring side as you describe :) Thanks a lot for your help and quick response! I really appreciate! Cheers!
Comment From: philwebb
We might be able to track beans that we've started ourselves rather than relying on the container ID
Comment From: philwebb
I spent a fair bit of time looking at this today and I don't think tracking beans will work. The problem is that the container may have been started by org.testcontainers.junit.jupiter.TestcontainersExtension and there's no way for us to track that.