Documentation for 0.6.0

This commit is contained in:
Tim Zöller 2022-03-25 22:59:14 +01:00
parent 791708bf51
commit a53cf9e271
6 changed files with 292 additions and 145 deletions

188
README.md
View file

@ -3,27 +3,32 @@
[![Clojars Project](http://clojars.org/clj-test-containers/latest-version.svg)](http://clojars.org/clj-test-containers)
## What it is
This library is a lightweight wrapper around the [Testcontainers Java library](https://www.testcontainers.org/).
## What it isn't
This library does not provide tools to include testcontainers in your testing lifecycle. As there are many different test tools with different approaches to testing in the clojure world, handling the lifecycle is up to you.
This library does not provide tools to include testcontainers in your testing lifecycle. As there are many different
test tools with different approaches to testing in the clojure world, handling the lifecycle is up to you.
## Integration with test runners
There is an [experimental kaocha plugin](https://github.com/lambdaschmiede/kaocha-testcontainers-plugin) you can try out
## Usage
The library provides a set of functions to interact with the testcontainers. A simple example, how to create a container with a Docker label, could look like this:
The library provides a set of functions to interact with the testcontainers. A simple example, how to create a container
with a Docker label, could look like this:
```clojure
(require '[clj-test-containers.core :as tc])
(def container (-> (tc/create {:image-name "postgres:12.1"
(def container (-> (tc/create {:image-name "postgres:12.1"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" "verysecret"}})
(tc/bind-filesystem! {:host-path "/tmp"
:env-vars {"POSTGRES_PASSWORD" "verysecret"}})
(tc/bind-filesystem! {:host-path "/tmp"
:container-path "/opt"
:mode :read-only})
:mode :read-only})
(tc/start!)))
(do-database-testing (:host container)
@ -38,10 +43,10 @@ If you'd rather create a container from a Dockerfile in your project, it could l
(require '[clj-test-containers.core :as tc])
(def container (-> (tc/create-from-docker-file {:env-vars {"FOO" "bar"}
:exposed-ports [80]
:docker-file "resources/Dockerfile"})
(tc/start!)))
(def container (-> (tc/create-from-docker-file {:env-vars {"FOO" "bar"}
:exposed-ports [80]
:docker-file "resources/Dockerfile"})
(tc/start!)))
```
If you prefer to use prebuilt containers from the Testcontainers project, you can do it like this
@ -50,14 +55,15 @@ If you prefer to use prebuilt containers from the Testcontainers project, you ca
(require '[clj-test-containers.core :as tc])
(:import [org.testcontainers.containers PostgreSQLContainer])
(def container (-> (tc/init {:container (PostgreSQLContainer. "postgres:12.2")
:exposed-ports [5432]})
(tc/start!)))
(def container (-> (tc/init {:container (PostgreSQLContainer. "postgres:12.2")
:exposed-ports [5432]})
(tc/start!)))
```
## Functions and Properties
### create
Creates a testcontainers instance from a given Docker label and returns them
#### Config parameters:
@ -87,31 +93,32 @@ Creates a testcontainers instance from a given Docker label and returns them
#### Example:
```clojure
(create {:image-name "alpine:3.2"
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}
:network (create-network)
(create {:image-name "alpine:3.2"
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}
:network (create-network)
:network-aliases ["api-server"]
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
```
#### Example using wait-for and healthcheck:
```clojure
(create {:image-name "alpine:3.2"
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}
:network (create-network)
(create {:image-name "alpine:3.2"
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}
:network (create-network)
:network-aliases ["api-server"]
:wait-for {:strategy :health}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
:wait-for {:strategy :health}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
```
### init
Initializes a given Testcontainer, which was e.g. provided by a library
#### Config parameters:
@ -127,6 +134,7 @@ Initializes a given Testcontainer, which was e.g. provided by a library
| `:wait-for` | Map | A map containing the wait strategy to use and the condition to check for |
| `:log-to` | Map | A map containing the log strategy to use, e.g. {:log-strategy string} |
| | | |
#### Result:
| Key | Type | Description |
@ -142,28 +150,29 @@ Initializes a given Testcontainer, which was e.g. provided by a library
```clojure
;; PostgreSQL container needs a separate library! This is not included.
(init {:container (org.testcontainers.containers.PostgreSQLContainer)
(init {:container (org.testcontainers.containers.PostgreSQLContainer)
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
:env-vars {"MAGIC_NUMBER" "42"}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
```
#### Example using wait-for and a log message:
```clojure
;; PostgreSQL container needs a separate library! This is not included.
(init {:container (org.testcontainers.containers.PostgreSQLContainer)
(init {:container (org.testcontainers.containers.PostgreSQLContainer)
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}
:wait-for {:strategy :log :message "accept connections"}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
:env-vars {"MAGIC_NUMBER" "42"}
:wait-for {:strategy :log :message "accept connections"}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
```
### create-from-docker-file
Creates a testcontainer from a Dockerfile
#### Config parameters:
@ -179,6 +188,7 @@ Creates a testcontainer from a Dockerfile
| `:wait-for` | Map | A map containing the wait strategy to use and the condition to check for |
| `:log-to` | Map | A map containing the log strategy to use, e.g. {:log-strategy string} |
| | | |
#### Result:
| Key | Type | Description |
@ -193,17 +203,18 @@ Creates a testcontainer from a Dockerfile
#### Example:
```clojure
(create-from-docker-file {:docker-file "resources/Dockerfile"
(create-from-docker-file {:docker-file "resources/Dockerfile"
:exposed-ports [5432]
:env-vars {"MAGIC_NUMBER" "42"}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
:env-vars {"MAGIC_NUMBER" "42"}
:command ["/bin/sh"
"-c"
"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p 80; done"]})
```
---
### start!
Starts the Testcontainer, which was defined by `create`
#### Config parameters:
@ -215,6 +226,7 @@ Starts the Testcontainer, which was defined by `create`
| | | |
#### Result:
| Key | Type | Description |
| ------------- | :------------- | :----- |
| `:container` | `org.testcontainers.containers.Container` | The Testcontainers instance, accessible for everything this library doesn't provide (yet) |
@ -227,17 +239,17 @@ Starts the Testcontainer, which was defined by `create`
#### Example:
```clojure
(def container (create {:image-name "alpine:3.2"
(def container (create {:image-name "alpine:3.2"
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}}))
:env-vars {"MAGIC_NUMBER" "42"}}))
(start! container)
```
---
### stop!
Stops the Testcontainer, which was defined by `create`
#### Config parameters:
@ -248,14 +260,15 @@ Stops the Testcontainer, which was defined by `create`
| `container-config` | Map, mandatory | Return value of the `create` function |
#### Result:
The `container-config`
#### Example:
```clojure
(def container (create {:image-name "alpine:3.2"
(def container (create {:image-name "alpine:3.2"
:exposed-ports [80]
:env-vars {"MAGIC_NUMBER" "42"}}))
:env-vars {"MAGIC_NUMBER" "42"}}))
(start! container)
(stop! container)
@ -263,37 +276,37 @@ The `container-config`
---
### map-classpath-resource!
Maps a resource from your classpath into the containers file system
#### Config parameters:
| Key | Type | Description |
| Key | Type | Description |
| ------------- |:------------- | :-----|
| First parameter: | | |
| `container-config`| Map, mandatory | Return value of the `create` function |
| Second parameter: | | |
| `:resource-path` | String, mandatory | Path of your classpath resource |
| `:container-path` | String, mandatory | Path, to which the resource should be mapped |
| `:mode` | Keyword, mandatory | `:read-only` or `:read-write` |
| `:resource-path` | String, mandatory | Path of your classpath resource |
| `:container-path` | String, mandatory | Path, to which the resource should be mapped |
| `:mode` | Keyword, mandatory | `:read-only` or `:read-write` |
#### Result:
The `container-config`
#### Example:
```clojure
(map-classpath-resource! container {:resource-path "test.sql"
:container-path "/opt/test.sql"
:mode :read-only})
(map-classpath-resource! container {:resource-path "test.sql"
:container-path "/opt/test.sql"
:mode :read-only})
```
---
### bind-filesystem!
Binds a path from your local filesystem into the Docker container as a volume
#### Config parameters:
@ -307,51 +320,51 @@ Binds a path from your local filesystem into the Docker container as a volume
| `:container-path` | String, mandatory | Path, to which the resource should be mapped |
| `:mode` | Keyword, mandatory | `:read-only` or `:read-write` |
#### Result:
The `container-config`
#### Example:
```clojure
(bind-filesystem! container {:host-path "."
(bind-filesystem! container {:host-path "."
:container-path "/opt"
:mode :read-only})
:mode :read-only})
```
---
### copy-file-to-container!
Copies a file from your filesystem or classpath into the running container
#### Config parameters:
| Key | Type | Description |
| Key | Type | Description |
| ------------- |:------------- | :-----|
| First parameter: | | |
| `container-config`| Map, mandatory | Return value of the `create` function |
| Second parameter: | | |
| `:path` | String, mandatory | Path to a classpath resource *or* file on your filesystem |
| `:host-path` | String, mandatory | Path, to which the file should be copied |
| `:type` | Keyword, mandatory | `:classpath-resource` or `:host-path` |
| `:path` | String, mandatory | Path to a classpath resource *or* file on your filesystem |
| `:host-path` | String, mandatory | Path, to which the file should be copied |
| `:type` | Keyword, mandatory | `:classpath-resource` or `:host-path` |
#### Result:
The `container-config`
#### Example:
```clojure
(copy-file-to-container! container {:path "test.sql"
(copy-file-to-container! container {:path "test.sql"
:container-path "/opt/test.sql"
:type :host-path})
:type :host-path})
```
---
### execute-command!
Executes a command in the running container, and returns the result
#### Config parameters:
@ -363,9 +376,8 @@ Executes a command in the running container, and returns the result
| Second parameter: |   |   |
| `command` | Vector with Strings, mandatory | A vector containing the command and its parameters |
#### Result:
| Key | Type | Description |
| ------------- | :------------- | :----- |
| `:exit-code` | int | Exit code of the executed command |
@ -379,8 +391,8 @@ Executes a command in the running container, and returns the result
```
### create-network
Creates a network. The optional map accepts config values for enabling ipv6 and setting the driver
Creates a network. The optional map accepts config values for enabling ipv6 and setting the driver
#### Config parameters:
@ -389,9 +401,8 @@ Creates a network. The optional map accepts config values for enabling ipv6 and
| `:ipv6` | boolean | Should the network enable IPv6? |
| `:driver` | String | The network driver used by Docker, e.g. `bridge` or `host` |
#### Result:
| Key | Type | Description |
| ------------- | :------------- | :----- |
| `:network` | `org.testcontainers.containers.Network` | The instance of the network |
@ -403,7 +414,7 @@ Creates a network. The optional map accepts config values for enabling ipv6 and
```clojure
;;Create with config
(create-network {:ipv6 false
(create-network {:ipv6 false
:driver "overlay"})
;;Create with default config
@ -411,27 +422,34 @@ Creates a network. The optional map accepts config values for enabling ipv6 and
```
### perform-cleanup!
Stops and removes all containers which were created in the JVM, including the REPL session you are in. This is helpful, if you are exploring functionality with containers in the REPL, and create lots of instances on the fly without stopping them. Testcontainers will remove all containers upon JVM shutdown, but the REPL keeps the JVM alive for a long time.
#### Config parameters:
Stops and removes all containers which were created in the JVM, including the REPL session you are in. This is helpful,
if you are exploring functionality with containers in the REPL, and create lots of instances on the fly without stopping
them. Testcontainers will remove all containers upon JVM shutdown, but the REPL keeps the JVM alive for a long time.
#### Config parameters:
None
#### Result:
#### Result:
None
#### Example:
```clojure
(perform-cleanup!)
```
### dump-logs
Call on a started container.
Provided logging was enabled for a container, returns the given log presentation, e.g. as a string
Call on a started container. Provided logging was enabled for a container, returns the given log presentation, e.g. as a
string
| Key | Type | Description |
| ------------- | :------------- | :----- |
| `container-config` | Map, mandatory | The configuration describing the container for which the log should be retrieved |
## License
Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

View file

@ -1,27 +1,38 @@
# Introduction
## Who is this library for?
This library is meant for Clojure developers who want to write integration tests without having to worry about the infrastructure of the application.
This library is meant for Clojure developers who want to write integration tests without having to worry about the
infrastructure of the application.
## What are Testcontainers?
Depending on the complexity of your application, setting up the infrastructure for integration tests is not a simple task. Even if you only need a single database for the integration tests, you need to make it available to every system that executes the tests. But often, one database is not enough and you need to integrate with Webservices, Message Queues, Search Indexes, Caches… Testcontainers try to solve this problem: Very simply put, the testcontainers Java library provides an interface to interact with Docker and enables developers to easily bring up Docker containers for executing tests, and tearing them down again, afterwards. See more at [https://www.testcontainers.org/](https://www.testcontainers.org/)
Depending on the complexity of your application, setting up the infrastructure for integration tests is not a simple
task. Even if you only need a single database for the integration tests, you need to make it available to every system
that executes the tests. But often, one database is not enough and you need to integrate with Webservices, Message
Queues, Search Indexes, Caches… Testcontainers try to solve this problem: Very simply put, the testcontainers Java
library provides an interface to interact with Docker and enables developers to easily bring up Docker containers for
executing tests, and tearing them down again, afterwards. See more
at [https://www.testcontainers.org/](https://www.testcontainers.org/)
## Why do we need a Clojure wrapper?
As Testcontainers is a Java library, we do not *need* a Clojure wrapper to work with it. It is completely possible to use it directly via Java interop code:
```java
(-> (org.testcontainers.containers.GenericContainer. "postgres:12.2")
(.withExposedPorts (into-array Integer [(int 5432)]))
(.withEnv "POSTGRES_PASSSWORD" pw)
(.start))
```
But doing so is quite wordy and requires developers to use a lot of methods that manipulate a java instance.
As Testcontainers is a Java library, we do not *need* a Clojure wrapper to work with it. It is completely possible to
use it directly via Java interop code:
```clojure
(-> (tc/create {:image-name "postgres:12.1"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" pw}})
tc/start!)
(-> (org.testcontainers.containers.GenericContainer. "postgres:12.2")
(.withExposedPorts (into-array Integer [(int 5432)]))
(.withEnv "POSTGRES_PASSSWORD" pw)
(.start))
```
But doing so is quite wordy and requires developers to use a lot of methods that manipulate a java instance.
```clojure
(-> (tc/create {:image-name "postgres:12.1"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" pw}})
tc/start!)
```

View file

@ -2,7 +2,8 @@
The list of functions included in the library until now is as following:
* `create`: Creates a new Testcontainers instance, accepts parameters for mapped ports, environment variables and a start command
* `create`: Creates a new Testcontainers instance, accepts parameters for mapped ports, environment variables and a
start command
* `map-classpath-resource!`: Maps a resource from your classpath into the containers file system
* `bind-filesystem!`: Binds a path from your local filesystem into the Docker container as a volume
* `start!`: Starts the container
@ -10,80 +11,88 @@ The list of functions included in the library until now is as following:
* `copy-file-to-container!`: Copies a file from your filesystem or classpath into the running container
* `execute-command!`: Executes a command in the running container, and returns the result
The functions accept and return a map structure, which enables us to operate them on the same data structure in a consistent way. The example shown with Java Interop above would look like this, when using the wrapped functions:
The functions accept and return a map structure, which enables us to operate them on the same data structure in a
consistent way. The example shown with Java Interop above would look like this, when using the wrapped functions:
```clojure
(require '[clj-test-containers.core :as tc])
(deftest db-integration-test
(testing "A simple PostgreSQL integration test"
(let [pw "db-pass"
postgres (-> (tc/create {:image-name "postgres:12.1"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" pw}}))]
(tc/start! postgres)
(let [datasource (jdbc/get-datasource {:dbtype "postgresql"
:dbname "postgres"
:user "postgres"
:password pw
:host (:host postgres)
:port (get (:mapped-ports container) 5432)})]
(is (= [{:one 1 :two 2}] (with-open [connection (jdbc/get-connection datasource)]
(jdbc/execute! connection ["SELECT 1 ONE, 2 TWO"])))))
(tc/stop! postgres))))
(testing "A simple PostgreSQL integration test"
(let [pw "db-pass"
postgres (-> (tc/create {:image-name "postgres:12.1"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" pw}}))]
(tc/start! postgres)
(let [datasource (jdbc/get-datasource {:dbtype "postgresql"
:dbname "postgres"
:user "postgres"
:password pw
:host (:host postgres)
:port (get (:mapped-ports container) 5432)})]
(is (= [{:one 1 :two 2}] (with-open [connection (jdbc/get-connection datasource)]
(jdbc/execute! connection ["SELECT 1 ONE, 2 TWO"])))))
(tc/stop! postgres))))
```
## Executing commands inside the container
The `execute-command` function enables us to run commands inside the container. The function accepts a container and a vector of strings as parameters, with the first string being the command, followed by potential parameters. The function returns a map with an `:exit-code`, `:stdout` and `:stderr`:
The `execute-command` function enables us to run commands inside the container. The function accepts a container and a
vector of strings as parameters, with the first string being the command, followed by potential parameters. The function
returns a map with an `:exit-code`, `:stdout` and `:stderr`:
```clojure
(execute-command! container ["whoami"])
> {:exit-code 0
:stdout "root"}
:stdout "root"}
```
## Mounting files into the container
For some test scenarios it can be helpful to mount files from your filesystem or the resource path of your application into the container, before it is started. This could be helpful if you want to load a dumpfile into your database, before executing the tests. You can do this with the functions `map-classpath-resource!` and `bind-filesystem!`:
For some test scenarios it can be helpful to mount files from your filesystem or the resource path of your application
into the container, before it is started. This could be helpful if you want to load a dumpfile into your database,
before executing the tests. You can do this with the functions `map-classpath-resource!` and `bind-filesystem!`:
```clojure
(map-classpath-resource! container
{:resource-path "test.sql"
(map-classpath-resource! container
{:resource-path "test.sql"
:container-path "/opt/test.sql"
:mode :read-only})
:mode :read-only})
```
```clojure
(bind-filesystem! {:host-path "."
:container-path "/opt"
:mode :read-only})
(bind-filesystem! {:host-path "."
:container-path "/opt"
:mode :read-only})
```
It is also possible to copy files into a running container instance:
```clojure
(copy-file-to-container! {:path "test.sql"
:container-path "/opt/test.sql"
:type :host-path})
(copy-file-to-container! {:path "test.sql"
:container-path "/opt/test.sql"
:type :host-path})
```
# Fixtures for Clojure Test
The above example creates a Testcontainers instance in the test function itself. If we did this for all of our integration tests, this would spin up a docker image for every test function, and tear it down again, afterwards. If we want to create one image for all tests in the same namespace, we can use Clojures [`use-fixtures`](https://clojuredocs.org/clojure.test/use-fixtures) function, which is described like this:
> Wrap test runs in a fixture function to perform setup and
teardown. Using a fixture-type of :each wraps every test
individually, while :once wraps the whole run in a single function.
The above example creates a Testcontainers instance in the test function itself. If we did this for all of our
integration tests, this would spin up a docker image for every test function, and tear it down again, afterwards. If we
want to create one image for all tests in the same namespace, we can use
Clojures [`use-fixtures`](https://clojuredocs.org/clojure.test/use-fixtures) function, which is described like this:
Assuming we have a function `initialize-db!` in our application which sets up a JDBC connection and stores it in an atom, a fixture for Testcontainers could look like this:
> Wrap test runs in a fixture function to perform setup and teardown. Using a fixture-type of :each wraps every test individually, while :once wraps the whole run in a single function.
Assuming we have a function `initialize-db!` in our application which sets up a JDBC connection and stores it in an
atom, a fixture for Testcontainers could look like this:
```clojure
(use-fixtures :once (fn [f]
(let [{pw "apassword"
postgres (tc/start! (tc/create {:image-name "postgres:12.2"
(let [{pw "apassword"
postgres (tc/start! (tc/create {:image-name "postgres:12.2"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" pw}}))}]
:env-vars {"POSTGRES_PASSWORD" pw}}))}]
(my-app/initialize-db! {:dbtype "postgresql"
:dbname "postgres"
:user "postgres"

96
doc/wait-strategies.md Normal file
View file

@ -0,0 +1,96 @@
# Wait strategies
Testcontainers provides a set of wait strategies which help us determine if and when a container is ready to accept
requests. Wait strategies are defined for the `:wait-for` key in the container configuration with the
key `:wait-strategy` determining which strategy to select. The `start!` function will block until the container is ready
and continue processing afterwards.
## HTTP Wait Strategy
The HTTP wait strategy will perform an HTTP call according to the following configuration and only continue if the
criteria is met.
| Parameter | Type | Description |
|-------------------|------------|---------------------------------------------------------|
| wait-strategy | Keyword | :http |
| path | String | The HTTP path to access |
| port | int | The HTTP port to access |
| method | String | The HTTP method to use (get, post, put...) |
| status-codes | seq of int | The status codes which mark a successful request |
| tls | boolean | Should TLS be used? |
| read-timeout | long | The duration in seconds the HTTP may take |
| basic-credentials | Map | {:username "User" :password "Password"} |
| headers | Map | HTTP Headers, e.g. {"Accept" "application/json"} |
| startup-timeout | long | The duration in seconds the container may take to start |
Example:
```clojure
(tc/create {:image-name "alpine:3.5"
:command ["/bin/sh"
"-c"
"while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done"]
:exposed-ports [8080]
:wait-for {:wait-strategy :http
:path "/"
:port 8080
:method "GET"
:status-codes [200]
:tls false
:read-timout 5
:headers {"Accept" "text/plain"}
:startup-timeout 20}})
```
## Health Wait Strategy
The Health Wait Strategy uses a health check defined in the Dockerfile to determine if the container is ready.
| Parameter | Type | Description |
|-----------------|---------|---------------------------------------------------------|
| wait-strategy | Keyword | :port |
| startup-timeout | long | The duration in seconds the container may take to start |
```clojure
(tc/create {:image-name "alpine:3.5"
:exposed-ports [8080]
:wait-for {:wait-strategy :health
:startup-timeout 20}})
```
## Log Wait Strategy
The Log Wait Strategy waits until a certain phrase appears in the Docker containers' log.
| Parameter | Type | Description |
|-----------------|---------|---------------------------------------------------------|
| wait-strategy | Keyword | :log |
| message | String | A substring of an expected line in the containers log |
| times | int | The number of times the predicate has to match |
| startup-timeout | long | The duration in seconds the container may take to start |
```clojure
(tc/create {:image-name "postgres:12.2"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" "pw"}
:wait-for {:wait-strategy :log
:message "accept connections"
:startup-timeout 10}})
```
## Port Wait Strategy
This strategy is the default selcted by Testcontainers if no wait strategy was defined. It waits for the first port in
the containers port mapping to be opened. It does not accept any parameters beside the `startup-timeout`
| Parameter | Type | Description |
|-----------------|---------|---------------------------------------------------------|
| wait-strategy | Keyword | :port |
| startup-timeout | long | The duration in seconds the container may take to start |
```clojure
(tc/create {:image-name "postgres:12.2"
:exposed-ports [5432]
:env-vars {"POSTGRES_PASSWORD" "pw"}
:wait-for {:wait-strategy :port}})
```

View file

@ -53,19 +53,20 @@
:tls true
:read-timeout 5
:basic-credentials {:username \"user\"
:password \"password\"}}
:password \"password\"
:startup-timeout 60}}
container)
```
## Health Strategy
The :health strategy only accepts a true or false value. This enables support
for Docker's healthcheck feature, whereby you can directly leverage the
healthy state of your container as your wait condition.
The :health strategy enables support for Docker's healthcheck feature,
whereby you can directly leverage the healthy state of your container as your wait condition.
Example:
```clojure
(wait {:wait-strategy :health :true} container)
(wait {:wait-strategy :health
:startup-timeout 60} container)
```
## Log Strategy
@ -77,7 +78,19 @@
```clojure
(wait {:wait-strategy :log
:message \"accept connections\"} container)
:message \"accept connections\"
:startup-timeout 60} container)
```
## Port Strategy
The port strategy waits for the first of the mapped ports to be opened. It only accepts the startup-timeout
value as a parameter.
Example:
```clojure
(wait {:wait-strategy :port
:startup-timeout 60} container
```"
:wait-strategy)

View file

@ -35,7 +35,7 @@
(s/def ::log
keyword?)
(s/def ::wait-strategy #{:http :health :log})
(s/def ::wait-strategy #{:http :health :port :log})
(s/def ::log-strategy #{:string})