-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add DockerHealthcheckWaitStrategy #618
Changes from 7 commits
184ca99
5dd6229
98ef3dd
5dc9bd1
e92538f
f03659a
c8fcbac
4de4253
79cc554
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.testcontainers.containers.wait.strategy; | ||
|
||
import org.rnorth.ducttape.TimeoutException; | ||
import org.rnorth.ducttape.unreliables.Unreliables; | ||
import org.testcontainers.containers.ContainerLaunchException; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* Wait strategy leveraging Docker's built-in healthcheck mechanism. | ||
* | ||
* @see <a href="https://docs.docker.com/engine/reference/builder/#healthcheck">https://docs.docker.com/engine/reference/builder/#healthcheck</a> | ||
*/ | ||
public class DockerHealthcheckWaitStrategy extends AbstractWaitStrategy { | ||
|
||
@Override | ||
protected void waitUntilReady() { | ||
|
||
try { | ||
Unreliables.retryUntilTrue((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, waitStrategyTarget::isHealthy); | ||
} catch (TimeoutException e) { | ||
throw new ContainerLaunchException("Timed out waiting for container to become healthy"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package org.testcontainers.containers.wait.strategy; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.testcontainers.containers.ContainerLaunchException; | ||
import org.testcontainers.containers.GenericContainer; | ||
import org.testcontainers.images.builder.ImageFromDockerfile; | ||
|
||
import java.time.Duration; | ||
|
||
import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows; | ||
|
||
public class DockerHealthcheckWaitStrategyTest { | ||
|
||
private GenericContainer container; | ||
|
||
@Before | ||
public void setUp() { | ||
// Using a Dockerfile here, since Dockerfile builder DSL doesn't support HEALTHCHECK | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitly, but another PR I assume? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure, up to you |
||
container = new GenericContainer(new ImageFromDockerfile() | ||
.withFileFromClasspath("write_file_and_loop.sh", "health-wait-strategy-dockerfile/write_file_and_loop.sh") | ||
.withFileFromClasspath("Dockerfile", "health-wait-strategy-dockerfile/Dockerfile")) | ||
.waitingFor(new DockerHealthcheckWaitStrategy().withStartupTimeout(Duration.ofSeconds(3))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason not to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, I'll change it. |
||
} | ||
|
||
@Test | ||
public void startsOnceHealthy() { | ||
container.start(); | ||
} | ||
|
||
@Test | ||
public void containerStartFailsIfContainerIsUnhealthy() { | ||
container.withCommand("tail", "-f", "/dev/null"); | ||
assertThrows("Container launch fails when unhealthy", ContainerLaunchException.class, container::start); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
FROM alpine:3.7 | ||
|
||
HEALTHCHECK --interval=1s CMD test -e /testfile | ||
|
||
COPY write_file_and_loop.sh write_file_and_loop.sh | ||
RUN chmod +x write_file_and_loop.sh | ||
|
||
CMD ["/write_file_and_loop.sh"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/bin/ash | ||
|
||
echo sleeping | ||
sleep 2 | ||
echo writing file | ||
touch /testfile | ||
|
||
while true; do sleep 1; done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Boolean.TRUE.equals(running)
;)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx, I think it's obvious that I'm not used to working with boxed primitives :D