External ports are cached between tests
csokol opened this issue · 1 comments
csokol commented
I'm facing a similar problem reported in #200. After a bit of debugging, it seems like the rule doesn't call stop/start or the containers are cached in ContainerCache
between two tests. So if the rule runs docker compose down
then docker compose up
, the ports might change and this doesn't get reflected in the container objects.
I noticed this problem when trying to create a base class with a shared docker compose rule config.
For example:
docker-compose.yml
version: '2.1'
services:
redis:
image: redis:3.2-alpine
ports:
- "6379"
public abstract class Base {
@ClassRule
public static DockerComposeRule dockerComposeRule = DockerComposeRule.builder()
.file(new File("./docker-compose.yml")
.getAbsolutePath())
.waitingForService("redis", toHaveAllPortsOpen(), Duration.standardSeconds(10))
.build();
}
public class Foo1Test extends Base {
@Test
public void doit() {
Assert.assertTrue(true);
}
}
public class Foo2Test extends Base {
@Test
public void doit() {
Assert.assertTrue(true);
}
}
Here's the output when I run both tests:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running foo.Foo1Test
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.378 sec
Running foo.Foo2Test
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 12.753 sec <<< FAILURE!
foo.Foo2Test Time elapsed: 12.751 sec <<< ERROR!
java.lang.IllegalStateException: The cluster failed to pass a startup check: The following ports failed to open: [6379]
at com.palantir.docker.compose.connection.waiting.ClusterWait.waitUntilReady(ClusterWait.java:50)
at com.palantir.docker.compose.DockerComposeRule.lambda$before$0(DockerComposeRule.java:155)
at java.lang.Iterable.forEach(Iterable.java:75)
at com.palantir.docker.compose.DockerComposeRule.before(DockerComposeRule.java:155)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:46)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Results :
Tests in error:
foo.Foo2Test: The cluster failed to pass a startup check: The following ports failed to open: [6379]
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0
Any ideas on how to fix it?
csokol commented
For reference, I was able to find a hacky solution by resetting the container cache through reflection:
public class CustomDockerComposeRule extends ExternalResource {
private DockerComposeRule delegate;
public CustomDockerComposeRule(DockerComposeRule delegate) {
this.delegate = delegate;
}
@Override
protected void before() throws Throwable {
ContainerCache containerCache = delegate.containers().containerCache();
FieldUtils.writeField(containerCache, "containers", new HashMap<>(), true);
delegate.before();
}
@Override
protected void after() {
delegate.after();
}
}