Added :fn log strategy (#41)
This commit is contained in:
parent
a53cf9e271
commit
c42886ba56
6 changed files with 155 additions and 90 deletions
|
|
@ -1,6 +1,13 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
|
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
|
||||||
|
|
||||||
|
## [0.6.0] - 2022-03-26
|
||||||
|
### Changed
|
||||||
|
- [#55](https://github.com/javahippie/clj-test-containers/issues/55): Upgrade to latest Testcontainers version
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- [#42](https://github.com/javahippie/clj-test-containers/issues/42): Extend wait strategies
|
||||||
|
|
||||||
## [0.5.0] - 2021-08-18
|
## [0.5.0] - 2021-08-18
|
||||||
### Changed
|
### Changed
|
||||||
- [#49](https://github.com/javahippie/clj-test-containers/issues/49): Updated to latest Testcontainers version
|
- [#49](https://github.com/javahippie/clj-test-containers/issues/49): Updated to latest Testcontainers version
|
||||||
|
|
|
||||||
48
README.md
48
README.md
|
|
@ -68,16 +68,16 @@ Creates a testcontainers instance from a given Docker label and returns them
|
||||||
|
|
||||||
#### Config parameters:
|
#### Config parameters:
|
||||||
|
|
||||||
| Key | Type | Description |
|
| Key | Type | Description |
|
||||||
| ------------- | :------------- | :----- |
|
| ------------- | :------------- |:----------------------------------------------------------------------------------------------------|
|
||||||
| `:image-name` | String, mandatory | The name and label of an image, e.g. `postgres:12.2` |
|
| `:image-name` | String, mandatory | The name and label of an image, e.g. `postgres:12.2` |
|
||||||
| `:exposed-ports` | Vector with ints, mandatory | All ports which should be exposed and mapped to a local port |
|
| `:exposed-ports` | Vector with ints, mandatory | All ports which should be exposed and mapped to a local port |
|
||||||
| `:env-vars` | Map | A map with environment variables |
|
| `:env-vars` | Map | A map with environment variables |
|
||||||
| `:command` | Vector with strings | The start command of the container |
|
| `:command` | Vector with strings | The start command of the container |
|
||||||
| `:network` | Map | A map containing the configuration of a Docker Network (see: `create-network`) |
|
| `:network` | Map | A map containing the configuration of a Docker Network (see: `create-network`) |
|
||||||
| `:network-aliases` | Map | A list of alias names for the container on the network |
|
| `:network-aliases` | Map | A list of alias names for the container on the network |
|
||||||
| `:wait-for` | Map | A map containing the wait strategy to use and the condition to check for |
|
| `:wait-for` | Map | A map containing the [wait strategy](docs/wait-strategies.md) to use and the condition to check for |
|
||||||
| `:log-to` | Map | A map containing the log strategy to use, e.g. {:log-strategy string} |
|
| `:log-to` | Map | A map containing the [log strategy](docs/log-strategies.md) to use, e.g. {:log-strategy string} |
|
||||||
|
|
||||||
#### Result:
|
#### Result:
|
||||||
|
|
||||||
|
|
@ -123,22 +123,22 @@ Initializes a given Testcontainer, which was e.g. provided by a library
|
||||||
|
|
||||||
#### Config parameters:
|
#### Config parameters:
|
||||||
|
|
||||||
| Key | Type | Description |
|
| Key | Type | Description |
|
||||||
| ------------- | :------------- | :----- |
|
| ------------- | :------------- |:----------------------------------------------------------------------------------------------------|
|
||||||
| `:container` | `org.testcontainers.containers.GenericContainer`, mandatory | The name and label of an image, e.g. `postgres:12.2` |
|
| `:container` | `org.testcontainers.containers.GenericContainer`, mandatory | The name and label of an image, e.g. `postgres:12.2` |
|
||||||
| `:exposed-ports` | Vector with ints, mandatory | All ports which should be exposed and mapped to a local port |
|
| `:exposed-ports` | Vector with ints, mandatory | All ports which should be exposed and mapped to a local port |
|
||||||
| `:env-vars` | Map | A map with environment variables |
|
| `:env-vars` | Map | A map with environment variables |
|
||||||
| `:command` | Vector with strings | The start command of the container |
|
| `:command` | Vector with strings | The start command of the container |
|
||||||
| `:network` | Map | A map containing the configuration of a Docker Network (see: `create-network`) |
|
| `:network` | Map | A map containing the configuration of a Docker Network (see: `create-network`) |
|
||||||
| `:network-aliases` | Map | A list of alias names for the container on the network |
|
| `:network-aliases` | Map | A list of alias names for the container on the network |
|
||||||
| `:wait-for` | Map | A map containing the wait strategy to use and the condition to check for |
|
| `:wait-for` | Map | A map containing the [wait strategy](docs/wait-strategies.md) to use and the condition to check for |
|
||||||
| `:log-to` | Map | A map containing the log strategy to use, e.g. {:log-strategy string} |
|
| `:log-to` | Map | A map containing the [log strategy](docs/log-strategies.md) to use, e.g. {:log-strategy string} |
|
||||||
| | | |
|
| | | |
|
||||||
|
|
||||||
#### Result:
|
#### Result:
|
||||||
|
|
||||||
| Key | Type | Description |
|
| Key | Type | Description |
|
||||||
| ------------- | :------------- | :----- |
|
| ------------- | :------------- |:------------------------------------------------------------------------------------------|
|
||||||
| `:container` | `org.testcontainers.containers.Container` | The Testcontainers instance, accessible for everything this library doesn't provide (yet) |
|
| `:container` | `org.testcontainers.containers.Container` | The Testcontainers instance, accessible for everything this library doesn't provide (yet) |
|
||||||
| `:exposed-ports` | Vector with ints | Value of the same input parameter |
|
| `:exposed-ports` | Vector with ints | Value of the same input parameter |
|
||||||
| `:env-vars` | Map | Value of the same input parameter |
|
| `:env-vars` | Map | Value of the same input parameter |
|
||||||
|
|
@ -185,8 +185,8 @@ Creates a testcontainer from a Dockerfile
|
||||||
| `:command` | Vector with strings | The start command of the container |
|
| `:command` | Vector with strings | The start command of the container |
|
||||||
| `:network` | Map | A map containing the configuration of a Docker Network (see: `create-network`) |
|
| `:network` | Map | A map containing the configuration of a Docker Network (see: `create-network`) |
|
||||||
| `:network-aliases` | Map | A list of alias names for the container on the network |
|
| `:network-aliases` | Map | A list of alias names for the container on the network |
|
||||||
| `:wait-for` | Map | A map containing the wait strategy to use and the condition to check for |
|
| `:wait-for` | Map | A map containing the [wait strategy](docs/wait-strategies.md) to use and the condition to check for |
|
||||||
| `:log-to` | Map | A map containing the log strategy to use, e.g. {:log-strategy string} |
|
| `:log-to` | Map | A map containing the [log strategy](docs/log-strategies.md) to use, e.g. {:log-strategy string} |
|
||||||
| | | |
|
| | | |
|
||||||
|
|
||||||
#### Result:
|
#### Result:
|
||||||
|
|
|
||||||
34
doc/log-strategies.md
Normal file
34
doc/log-strategies.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Log strategies
|
||||||
|
|
||||||
|
This library offers two ways to access the logs of the running container: The :string strategy and the :fn strategy.
|
||||||
|
|
||||||
|
## String Strategy
|
||||||
|
|
||||||
|
The `:string` strategy sets up a function in the returned map, under the `string-log` key. This function enables the
|
||||||
|
dumping of the logs when passed to the `dump-logs` function.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
{:log-strategy :string}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, later in your program, you can access the logs thus:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(def container-config (tc/start! container))
|
||||||
|
(tc/dump-logs container-config)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Function Strategy
|
||||||
|
|
||||||
|
The `:fn` strategy accepts an additional parameter `:function` in the configuration map, which allows you to pass a
|
||||||
|
function to the Testcontainers log mechanism which accepts a single String parameter and gets called for every log line.
|
||||||
|
This way you can pass the container logging on to the logging library of your choice.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
{:log-strategy :fn
|
||||||
|
:function (fn [log-line] (println "From Container: " log-line)}
|
||||||
|
```
|
||||||
|
|
@ -23,7 +23,8 @@
|
||||||
[orchestra "2021.01.01-1"]
|
[orchestra "2021.01.01-1"]
|
||||||
[org.clojure/tools.namespace "1.2.0"]
|
[org.clojure/tools.namespace "1.2.0"]
|
||||||
[org.testcontainers/postgresql "1.16.3"]
|
[org.testcontainers/postgresql "1.16.3"]
|
||||||
[com.fzakaria/slf4j-timbre "0.3.21"]]
|
[com.fzakaria/slf4j-timbre "0.3.21"]
|
||||||
|
[nrepl "0.9.0"]]
|
||||||
:source-paths ["dev-src"]}}
|
:source-paths ["dev-src"]}}
|
||||||
|
|
||||||
:target-path "target/%s")
|
:target-path "target/%s")
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
GenericContainer
|
GenericContainer
|
||||||
Network)
|
Network)
|
||||||
(org.testcontainers.containers.output
|
(org.testcontainers.containers.output
|
||||||
|
BaseConsumer
|
||||||
|
OutputFrame
|
||||||
ToStringConsumer)
|
ToStringConsumer)
|
||||||
(org.testcontainers.containers.wait.strategy
|
(org.testcontainers.containers.wait.strategy
|
||||||
Wait)
|
Wait)
|
||||||
|
|
@ -34,64 +36,64 @@
|
||||||
|
|
||||||
(defmulti wait
|
(defmulti wait
|
||||||
"Sets a wait strategy to the container. Supports :http, :health and :log as
|
"Sets a wait strategy to the container. Supports :http, :health and :log as
|
||||||
strategies.
|
strategies.
|
||||||
|
|
||||||
## HTTP Strategy
|
## HTTP Strategy
|
||||||
The :http strategy will only accept the container as initialized if it can be
|
The :http strategy will only accept the container as initialized if it can be
|
||||||
accessed via HTTP. It accepts a path, a port, a vector of status codes, a
|
accessed via HTTP. It accepts a path, a port, a vector of status codes, a
|
||||||
boolean that specifies if TLS is enabled, a read timeout in seconds and a map
|
boolean that specifies if TLS is enabled, a read timeout in seconds and a map
|
||||||
with basic credentials, containing username and password. Only the path is
|
with basic credentials, containing username and password. Only the path is
|
||||||
required, all others are optional.
|
required, all others are optional.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
(wait {:wait-strategy :http
|
(wait {:wait-strategy :http
|
||||||
:port 80
|
:port 80
|
||||||
:path \"/\"
|
:path \"/\"
|
||||||
:status-codes [200 201]
|
:status-codes [200 201]
|
||||||
:tls true
|
:tls true
|
||||||
:read-timeout 5
|
:read-timeout 5
|
||||||
:basic-credentials {:username \"user\"
|
:basic-credentials {:username \"user\"
|
||||||
:password \"password\"
|
:password \"password\"
|
||||||
:startup-timeout 60}}
|
:startup-timeout 60}}
|
||||||
container)
|
container)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Health Strategy
|
## Health Strategy
|
||||||
The :health strategy enables support for Docker's healthcheck feature,
|
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.
|
whereby you can directly leverage the healthy state of your container as your wait condition.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
(wait {:wait-strategy :health
|
(wait {:wait-strategy :health
|
||||||
:startup-timeout 60} container)
|
:startup-timeout 60} container)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Log Strategy
|
## Log Strategy
|
||||||
The :log strategy accepts a message which simply causes the output of your
|
The :log strategy accepts a message which simply causes the output of your
|
||||||
container's log to be used in determining if the container is ready or not.
|
container's log to be used in determining if the container is ready or not.
|
||||||
The output is `grepped` against the log message.
|
The output is `grepped` against the log message.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
(wait {:wait-strategy :log
|
(wait {:wait-strategy :log
|
||||||
:message \"accept connections\"
|
:message \"accept connections\"
|
||||||
:startup-timeout 60} container)
|
:startup-timeout 60} container)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Port Strategy
|
## Port Strategy
|
||||||
The port strategy waits for the first of the mapped ports to be opened. It only accepts the startup-timeout
|
The port strategy waits for the first of the mapped ports to be opened. It only accepts the startup-timeout
|
||||||
value as a parameter.
|
value as a parameter.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
(wait {:wait-strategy :port
|
(wait {:wait-strategy :port
|
||||||
:startup-timeout 60} container
|
:startup-timeout 60} container
|
||||||
```"
|
```"
|
||||||
:wait-strategy)
|
:wait-strategy)
|
||||||
|
|
||||||
(defmethod wait :http
|
(defmethod wait :http
|
||||||
|
|
@ -278,27 +280,38 @@
|
||||||
:stderr (.getStderr result)}))
|
:stderr (.getStderr result)}))
|
||||||
|
|
||||||
(defmulti log
|
(defmulti log
|
||||||
"Sets a log strategy on the container as a means of accessing the container
|
"Sets a log strategy on the container as a means of accessing the container logs.
|
||||||
logs. It currently only supports a :string as the strategy to use.
|
|
||||||
|
|
||||||
## String Strategy
|
## String Strategy
|
||||||
The :string strategy sets up a function in the returned map, under the
|
The `:string` strategy sets up a function in the returned map, under the
|
||||||
`string-log` key. This function enables the dumping of the logs when passed to
|
`string-log` key. This function enables the dumping of the logs when passed to
|
||||||
the `dump-logs` function.
|
the `dump-logs` function.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
{:log-strategy :string}
|
{:log-strategy :string}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, later in your program, you can access the logs thus:
|
Then, later in your program, you can access the logs thus:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
(def container-config (tc/start! container))
|
(def container-config (tc/start! container))
|
||||||
(tc/dump-logs container-config)
|
(tc/dump-logs container-config)
|
||||||
```
|
```
|
||||||
"
|
|
||||||
|
## Function Strategy
|
||||||
|
The `:fn` strategy accepts an additional parameter `:function` in the configuration
|
||||||
|
map, which allows you to pass a function to the Testcontainers log mechanism
|
||||||
|
which accepts a single String parameter and gets called for every log line. This
|
||||||
|
way you can pass the container logging on to the logging library of your choice.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```clojure
|
||||||
|
{:log-strategy :fn
|
||||||
|
:function (fn [log-line] (println \"From Container: \" log-line)}
|
||||||
|
```
|
||||||
|
"
|
||||||
:log-strategy)
|
:log-strategy)
|
||||||
|
|
||||||
(defmethod log :string
|
(defmethod log :string
|
||||||
|
|
@ -309,9 +322,12 @@
|
||||||
(-> (.toUtf8String to-string-consumer)
|
(-> (.toUtf8String to-string-consumer)
|
||||||
(clojure.string/replace #"\n+" "\n")))}))
|
(clojure.string/replace #"\n+" "\n")))}))
|
||||||
|
|
||||||
(defmethod log :slf4j [_ _] nil) ; Not yet implemented
|
(defmethod log :fn [{:keys [function]} ^GenericContainer container]
|
||||||
|
(.followOutput container (proxy [BaseConsumer] []
|
||||||
|
(^void accept [^OutputFrame frame]
|
||||||
|
(function (.getUtf8String frame))))))
|
||||||
|
|
||||||
(defmethod log :default [_ _] nil) ; Not yet implemented
|
(defmethod log :default [_ _] nil)
|
||||||
|
|
||||||
(defn dump-logs
|
(defn dump-logs
|
||||||
"Dumps the logs found by invoking the function on the :string-log key"
|
"Dumps the logs found by invoking the function on the :string-log key"
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,20 @@
|
||||||
(is (nil? (:id stopped-container)))
|
(is (nil? (:id stopped-container)))
|
||||||
(is (nil? (:mapped-ports stopped-container)))))
|
(is (nil? (:mapped-ports stopped-container)))))
|
||||||
|
|
||||||
(testing "Testing log access to the container"
|
(testing "Testing log access to the container with string logs"
|
||||||
(let [container (sut/init {:container (PostgreSQLContainer. "postgres:12.2")
|
(let [container (sut/init {:container (PostgreSQLContainer. "postgres:12.2")
|
||||||
:log-to {:log-strategy :string}})
|
:log-to {:log-strategy :string}})
|
||||||
initialized-container (sut/start! container)]
|
initialized-container (sut/start! container)]
|
||||||
(Thread/sleep 500)
|
(Thread/sleep 500)
|
||||||
(is (includes? (sut/dump-logs initialized-container) "database system is ready to accept connections"))))
|
(is (includes? (sut/dump-logs initialized-container) "database system is ready to accept connections"))))
|
||||||
|
|
||||||
|
(testing "Testing log access to the container with function logs"
|
||||||
|
(let [logs (atom [])]
|
||||||
|
(sut/start! (sut/init {:container (PostgreSQLContainer. "postgres:12.2")
|
||||||
|
:log-to {:log-strategy :fn
|
||||||
|
:function #(swap! logs conj %)}}))
|
||||||
|
(is (filter #(includes? "database system is ready to accept connections" %) @logs))))
|
||||||
|
|
||||||
(testing "Testing basic testcontainer generic image initialisation with wait for log message"
|
(testing "Testing basic testcontainer generic image initialisation with wait for log message"
|
||||||
(let [container (sut/create {:image-name "postgres:12.2"
|
(let [container (sut/create {:image-name "postgres:12.2"
|
||||||
:exposed-ports [5432]
|
:exposed-ports [5432]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue