Add type hints to silence reflection warnings (#38)
* Run lein check on CI * Add type hints as appropriate; readability cleanups
This commit is contained in:
parent
167fa385a2
commit
dac2b1ba4b
3 changed files with 114 additions and 90 deletions
|
|
@ -36,6 +36,9 @@ jobs:
|
||||||
- ~/.m2
|
- ~/.m2
|
||||||
key: v1-dependencies-{{ checksum "project.clj" }}
|
key: v1-dependencies-{{ checksum "project.clj" }}
|
||||||
|
|
||||||
|
# check syntax and warn on reflection
|
||||||
|
- run: lein check
|
||||||
|
|
||||||
# run tests!
|
# run tests!
|
||||||
- run: lein test
|
- run: lein test
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,20 +20,22 @@
|
||||||
MountableFile)))
|
MountableFile)))
|
||||||
|
|
||||||
(defn- resolve-bind-mode
|
(defn- resolve-bind-mode
|
||||||
[bind-mode]
|
(^BindMode [bind-mode]
|
||||||
(if (= :read-write bind-mode)
|
(if (= :read-write bind-mode)
|
||||||
BindMode/READ_WRITE
|
BindMode/READ_WRITE
|
||||||
BindMode/READ_ONLY))
|
BindMode/READ_ONLY)))
|
||||||
|
|
||||||
(defmulti wait
|
(defmulti wait
|
||||||
"Sets a wait strategy to the container.
|
"Sets a wait strategy to the container. Supports :http, :health and :log as
|
||||||
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 accessed
|
The :http strategy will only accept the container as initialized if it can be
|
||||||
via HTTP. It accepts a path, a port, a vector of status codes, a boolean that specifies
|
accessed via HTTP. It accepts a path, a port, a vector of status codes, a
|
||||||
if TLS is enabled, a read timeout in seconds and a map with basic credentials, containing
|
boolean that specifies if TLS is enabled, a read timeout in seconds and a map
|
||||||
username and password. Only the path is required, all others are optional.
|
with basic credentials, containing username and password. Only the path is
|
||||||
|
required, all others are optional.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
|
|
@ -47,10 +49,12 @@
|
||||||
:password \"password\"}}
|
:password \"password\"}}
|
||||||
container)
|
container)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Health Strategy
|
## Health Strategy
|
||||||
The :health strategy only accepts a true or false value. This enables support for Docker's
|
The :health strategy only accepts a true or false value. This enables support
|
||||||
healthcheck feature, whereby you can directly leverage the healthy state of your container
|
for Docker's healthcheck feature, whereby you can directly leverage the
|
||||||
as your wait condition.
|
healthy state of your container as your wait condition.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
|
|
@ -58,9 +62,10 @@
|
||||||
```
|
```
|
||||||
|
|
||||||
## Log Strategy
|
## Log Strategy
|
||||||
The :log strategy accepts a message which simply causes the output of your container's log
|
The :log strategy accepts a message which simply causes the output of your
|
||||||
to be used in determining if the container is ready or not. The output is `grepped` against
|
container's log to be used in determining if the container is ready or not.
|
||||||
the log message.
|
The output is `grepped` against the log message.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
|
|
@ -70,7 +75,13 @@
|
||||||
:wait-strategy)
|
:wait-strategy)
|
||||||
|
|
||||||
(defmethod wait :http
|
(defmethod wait :http
|
||||||
[{:keys [path port status-codes tls read-timeout basic-credentials] :as options} container]
|
[{:keys [path
|
||||||
|
port
|
||||||
|
status-codes
|
||||||
|
tls
|
||||||
|
read-timeout
|
||||||
|
basic-credentials] :as options}
|
||||||
|
^GenericContainer container]
|
||||||
(let [for-http (Wait/forHttp path)]
|
(let [for-http (Wait/forHttp path)]
|
||||||
(when port
|
(when port
|
||||||
(.forPort for-http port))
|
(.forPort for-http port))
|
||||||
|
|
@ -82,23 +93,23 @@
|
||||||
(.usingTls for-http))
|
(.usingTls for-http))
|
||||||
|
|
||||||
(when read-timeout
|
(when read-timeout
|
||||||
(.withReadTimeout (java.time.Duration/ofSeconds read-timeout)))
|
(.withReadTimeout for-http (java.time.Duration/ofSeconds read-timeout)))
|
||||||
|
|
||||||
(when basic-credentials
|
(when basic-credentials
|
||||||
(let [{username :username password :password} basic-credentials]
|
(let [{username :username password :password} basic-credentials]
|
||||||
(.withBasicCredentials username password)))
|
(.withBasicCredentials for-http username password)))
|
||||||
|
|
||||||
(.waitingFor container for-http)
|
(.waitingFor container for-http)
|
||||||
|
|
||||||
{:wait-for-http (dissoc options :strategy)}))
|
{:wait-for-http (dissoc options :strategy)}))
|
||||||
|
|
||||||
(defmethod wait :health
|
(defmethod wait :health
|
||||||
[_ container]
|
[_ ^GenericContainer container]
|
||||||
(.waitingFor container (Wait/forHealthcheck))
|
(.waitingFor container (Wait/forHealthcheck))
|
||||||
{:wait-for-healthcheck true})
|
{:wait-for-healthcheck true})
|
||||||
|
|
||||||
(defmethod wait :log
|
(defmethod wait :log
|
||||||
[{:keys [message]} container]
|
[{:keys [message]} ^GenericContainer container]
|
||||||
(let [log-message (str ".*" message ".*\\n")]
|
(let [log-message (str ".*" message ".*\\n")]
|
||||||
(.waitingFor container (Wait/forLogMessage log-message 1))
|
(.waitingFor container (Wait/forLogMessage log-message 1))
|
||||||
{:wait-for-log-message log-message}))
|
{:wait-for-log-message log-message}))
|
||||||
|
|
@ -111,20 +122,27 @@
|
||||||
|
|
||||||
(defn init
|
(defn init
|
||||||
"Sets the properties for a testcontainer instance"
|
"Sets the properties for a testcontainer instance"
|
||||||
[{:keys [container exposed-ports env-vars command network network-aliases wait-for] :as init-options}]
|
[{:keys [^GenericContainer container
|
||||||
|
exposed-ports
|
||||||
|
env-vars
|
||||||
|
command
|
||||||
|
network
|
||||||
|
network-aliases
|
||||||
|
wait-for] :as init-options}]
|
||||||
|
|
||||||
(.setExposedPorts container (map int exposed-ports))
|
(.setExposedPorts container (map int exposed-ports))
|
||||||
|
|
||||||
(run! (fn [[k v]] (.addEnv container k v)) env-vars)
|
(doseq [[k v] env-vars]
|
||||||
|
(.addEnv container k v))
|
||||||
|
|
||||||
(when command
|
(when command
|
||||||
(.setCommand container (into-array String command)))
|
(.setCommand container ^"[Ljava.lang.String;" (into-array String command)))
|
||||||
|
|
||||||
(when network
|
(when network
|
||||||
(.setNetwork container (:network network)))
|
(.setNetwork container (:network network)))
|
||||||
|
|
||||||
(when network-aliases
|
(when network-aliases
|
||||||
(.setNetworkAliases container (java.util.ArrayList. network-aliases)))
|
(.setNetworkAliases container network-aliases))
|
||||||
|
|
||||||
(merge init-options {:container container
|
(merge init-options {:container container
|
||||||
:exposed-ports (vec (.getExposedPorts container))
|
:exposed-ports (vec (.getExposedPorts container))
|
||||||
|
|
@ -139,72 +157,74 @@
|
||||||
(defn create
|
(defn create
|
||||||
"Creates a generic testcontainer and sets its properties"
|
"Creates a generic testcontainer and sets its properties"
|
||||||
[{:keys [image-name] :as options}]
|
[{:keys [image-name] :as options}]
|
||||||
(->> (GenericContainer. image-name)
|
(->> (GenericContainer. ^String image-name)
|
||||||
(assoc options :container)
|
(assoc options :container)
|
||||||
init))
|
init))
|
||||||
|
|
||||||
(defn create-from-docker-file
|
(defn create-from-docker-file
|
||||||
"Creates a testcontainer from a provided Dockerfile"
|
"Creates a testcontainer from a provided Dockerfile"
|
||||||
[{:keys [docker-file] :as options}]
|
[{:keys [docker-file] :as options}]
|
||||||
(->> (.withDockerfile (ImageFromDockerfile.) (Paths/get "." (into-array [docker-file])))
|
(->> (.withDockerfile (ImageFromDockerfile.)
|
||||||
|
(Paths/get "." (into-array [docker-file])))
|
||||||
(GenericContainer.)
|
(GenericContainer.)
|
||||||
(assoc options :container)
|
(assoc options :container)
|
||||||
init))
|
init))
|
||||||
|
|
||||||
(defn map-classpath-resource!
|
(defn map-classpath-resource!
|
||||||
"Maps a resource in the classpath to the given container path. Should be called before starting the container!"
|
"Maps a resource in the classpath to the given container path. Should be
|
||||||
[container-config
|
called before starting the container!"
|
||||||
{:keys [resource-path container-path mode]}]
|
[{:keys [^GenericContainer container] :as container-config}
|
||||||
(assoc container-config :container (.withClasspathResourceMapping (:container container-config)
|
{:keys [^String resource-path ^String container-path mode]}]
|
||||||
|
(assoc container-config
|
||||||
|
:container
|
||||||
|
(.withClasspathResourceMapping container
|
||||||
resource-path
|
resource-path
|
||||||
container-path
|
container-path
|
||||||
(resolve-bind-mode mode))))
|
(resolve-bind-mode mode))))
|
||||||
|
|
||||||
(defn bind-filesystem!
|
(defn bind-filesystem!
|
||||||
"Binds a source from the filesystem to the given container path. Should be called before starting the container!"
|
"Binds a source from the filesystem to the given container path. Should be
|
||||||
[container-config {:keys [host-path container-path mode]}]
|
called before starting the container!"
|
||||||
|
[{:keys [^GenericContainer container] :as container-config}
|
||||||
|
{:keys [^String host-path ^String container-path mode]}]
|
||||||
(assoc container-config
|
(assoc container-config
|
||||||
:container (.withFileSystemBind (:container container-config)
|
:container
|
||||||
|
(.withFileSystemBind container
|
||||||
host-path
|
host-path
|
||||||
container-path
|
container-path
|
||||||
(resolve-bind-mode mode))))
|
(resolve-bind-mode mode))))
|
||||||
|
|
||||||
(defn copy-file-to-container!
|
(defn copy-file-to-container!
|
||||||
"Copies a file into the running container"
|
"Copies a file into the running container"
|
||||||
[container-config
|
[{:keys [^GenericContainer container] :as container-config}
|
||||||
{:keys [container-path path type]}]
|
{:keys [^String container-path ^String path type]}]
|
||||||
(let [mountable-file (cond
|
(let [^MountableFile mountable-file
|
||||||
(= :classpath-resource type)
|
(case type
|
||||||
(MountableFile/forClasspathResource path)
|
:classpath-resource (MountableFile/forClasspathResource path)
|
||||||
|
:host-path (MountableFile/forHostPath path))]
|
||||||
(= :host-path type)
|
|
||||||
(MountableFile/forHostPath path)
|
|
||||||
:else
|
|
||||||
:error)]
|
|
||||||
(assoc container-config
|
(assoc container-config
|
||||||
:container
|
:container
|
||||||
(.withCopyFileToContainer (:container container-config)
|
(.withCopyFileToContainer container
|
||||||
mountable-file
|
mountable-file
|
||||||
container-path))))
|
container-path))))
|
||||||
|
|
||||||
(defn execute-command!
|
(defn execute-command!
|
||||||
"Executes a command in the container, and returns the result"
|
"Executes a command in the container, and returns the result"
|
||||||
[container-config command]
|
[{:keys [^GenericContainer container]} command]
|
||||||
(let [container (:container container-config)
|
(let [result (.execInContainer container (into-array command))]
|
||||||
result (.execInContainer container
|
|
||||||
(into-array command))]
|
|
||||||
{:exit-code (.getExitCode result)
|
{:exit-code (.getExitCode result)
|
||||||
:stdout (.getStdout result)
|
:stdout (.getStdout result)
|
||||||
:stderr (.getStderr result)}))
|
:stderr (.getStderr result)}))
|
||||||
|
|
||||||
(defmulti log
|
(defmulti log
|
||||||
"Sets a log strategy on the container as a means of accessing the container logs.
|
"Sets a log strategy on the container as a means of accessing the container
|
||||||
It currently only supports a :string as the strategy to use.
|
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 `string-log`
|
The :string strategy sets up a function in the returned map, under the
|
||||||
key. This function enables the dumping of the logs when passed to the `dump-logs`
|
`string-log` key. This function enables the dumping of the logs when passed to
|
||||||
function.
|
the `dump-logs` function.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
|
|
@ -221,7 +241,7 @@
|
||||||
:log-strategy)
|
:log-strategy)
|
||||||
|
|
||||||
(defmethod log :string
|
(defmethod log :string
|
||||||
[_ container]
|
[_ ^GenericContainer container]
|
||||||
(let [to-string-consumer (ToStringConsumer.)]
|
(let [to-string-consumer (ToStringConsumer.)]
|
||||||
(.followOutput container to-string-consumer)
|
(.followOutput container to-string-consumer)
|
||||||
{:string-log (fn []
|
{:string-log (fn []
|
||||||
|
|
@ -238,26 +258,26 @@
|
||||||
((:string-log container-config)))
|
((:string-log container-config)))
|
||||||
|
|
||||||
(defn start!
|
(defn start!
|
||||||
"Starts the underlying testcontainer instance and adds new values to the response map, e.g. :id and :first-mapped-port"
|
"Starts the underlying testcontainer instance and adds new values to the
|
||||||
[container-config]
|
response map, e.g. :id and :first-mapped-port"
|
||||||
(let [{:keys [container log-to]} container-config]
|
[{:keys [^GenericContainer container
|
||||||
|
log-to
|
||||||
|
exposed-ports] :as container-config}]
|
||||||
(.start container)
|
(.start container)
|
||||||
(-> (merge container-config
|
(let [map-port (fn map-port
|
||||||
{:id (.getContainerId container)
|
[port]
|
||||||
:mapped-ports (into {}
|
[port (.getMappedPort container port)])
|
||||||
(map (fn [port] [port (.getMappedPort container port)])
|
mapped-ports (into {} (map map-port) exposed-ports)]
|
||||||
(:exposed-ports container-config)))}
|
(-> container-config
|
||||||
|
(merge {:id (.getContainerId container) :mapped-ports mapped-ports}
|
||||||
(log log-to container))
|
(log log-to container))
|
||||||
(dissoc :log-to))))
|
(dissoc :log-to))))
|
||||||
|
|
||||||
(defn stop!
|
(defn stop!
|
||||||
"Stops the underlying container"
|
"Stops the underlying container"
|
||||||
[container-config]
|
[{:keys [^GenericContainer container] :as container-config}]
|
||||||
(.stop (:container container-config))
|
(.stop container)
|
||||||
(-> container-config
|
(dissoc container-config :id :string-log :mapped-ports))
|
||||||
(dissoc :id)
|
|
||||||
(dissoc :string-log)
|
|
||||||
(dissoc :mapped-ports)))
|
|
||||||
|
|
||||||
(s/fdef create-network
|
(s/fdef create-network
|
||||||
:args (s/alt :nullary (s/cat)
|
:args (s/alt :nullary (s/cat)
|
||||||
|
|
@ -266,7 +286,8 @@
|
||||||
:ret ::cs/network)
|
:ret ::cs/network)
|
||||||
|
|
||||||
(defn create-network
|
(defn 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"
|
||||||
([]
|
([]
|
||||||
(create-network {}))
|
(create-network {}))
|
||||||
([{:keys [ipv6 driver]}]
|
([{:keys [ipv6 driver]}]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
(s/def ::container
|
(s/def ::container
|
||||||
(s/with-gen #(instance? GenericContainer %)
|
(s/with-gen #(instance? GenericContainer %)
|
||||||
#(gen/fmap (fn [image-name] (GenericContainer. image-name))
|
#(gen/fmap (fn [^String image-name] (GenericContainer. image-name))
|
||||||
(gen/string-alphanumeric))))
|
(gen/string-alphanumeric))))
|
||||||
|
|
||||||
(s/def ::exposed-ports
|
(s/def ::exposed-ports
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue