From ea854767ae78c530c4139decd79a795f85539fee Mon Sep 17 00:00:00 2001 From: David Harrigan Date: Thu, 24 Sep 2020 18:23:12 +0100 Subject: [PATCH] Add support for a container wait strategy. (#31) For review. -=david=- --- src/clj_test_containers/core.clj | 36 +++++++++++++++++----- src/clj_test_containers/spec/container.clj | 20 ++++++++++++ src/clj_test_containers/spec/core.clj | 11 ++++++- test/clj_test_containers/core_test.clj | 14 +++++++++ 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/clj_test_containers/core.clj b/src/clj_test_containers/core.clj index e29a3a6..3bbdbfd 100644 --- a/src/clj_test_containers/core.clj +++ b/src/clj_test_containers/core.clj @@ -13,7 +13,9 @@ (org.testcontainers.images.builder ImageFromDockerfile) (org.testcontainers.utility - MountableFile))) + MountableFile) + (org.testcontainers.containers.wait.strategy + Wait))) (defn- resolve-bind-mode [bind-mode] @@ -21,13 +23,33 @@ BindMode/READ_WRITE BindMode/READ_ONLY)) +(defmulti wait :strategy) + +(defmethod wait :http + [{:keys [path]} container] + (.waitingFor container (Wait/forHttp path)) + {:wait-for-http path}) + +(defmethod wait :health + [_ container] + (.waitingFor container (Wait/forHealthcheck)) + {:wait-for-healthcheck true}) + +(defmethod wait :log + [{:keys [message]} container] + (let [log-message (str ".*" message ".*\\n")] + (.waitingFor container (Wait/forLogMessage log-message 1)) + {:wait-for-log-message log-message})) + +(defmethod wait :default [_ _] nil) + (s/fdef init :args (s/cat :init-options ::cs/init-options) :ret ::cs/container) (defn init "Sets the properties for a testcontainer instance" - [{:keys [container exposed-ports env-vars command network network-aliases]}] + [{:keys [container exposed-ports env-vars command network network-aliases wait-for]}] (.setExposedPorts container (map int exposed-ports)) @@ -42,11 +64,11 @@ (when network-aliases (.setNetworkAliases container (java.util.ArrayList. network-aliases))) - {:container container - :exposed-ports (vec (.getExposedPorts container)) - :env-vars (into {} (.getEnvMap container)) - :host (.getHost container) - :network network}) + (merge {:container container + :exposed-ports (vec (.getExposedPorts container)) + :env-vars (into {} (.getEnvMap container)) + :host (.getHost container) + :network network} (wait wait-for container))) (s/fdef create :args (s/cat :create-options ::cs/create-options) diff --git a/src/clj_test_containers/spec/container.clj b/src/clj_test_containers/spec/container.clj index 6714253..8d8d73a 100644 --- a/src/clj_test_containers/spec/container.clj +++ b/src/clj_test_containers/spec/container.clj @@ -25,3 +25,23 @@ (s/def ::image-name string?) + +(s/def ::http + keyword?) + +(s/def ::health + keyword?) + +(s/def ::log + keyword?) + +(s/def ::strategy #{:http :health :log}) + +(s/def ::path + string?) + +(s/def ::message + string?) + +(s/def ::check + boolean?) diff --git a/src/clj_test_containers/spec/core.clj b/src/clj_test_containers/spec/core.clj index cfead32..416842e 100644 --- a/src/clj_test_containers/spec/core.clj +++ b/src/clj_test_containers/spec/core.clj @@ -4,6 +4,12 @@ [clj-test-containers.spec.network :as csn] [clojure.spec.alpha :as s])) +(s/def ::wait-for + (s/keys :req-un [::csc/strategy] + :opt-un [::csc/path + ::csc/message + ::csc/check])) + (s/def ::network (s/nilable (s/keys :req-un [::csn/network ::csn/name @@ -15,7 +21,8 @@ ::csc/exposed-ports ::csc/env-vars ::csc/host] - :opt-un [::network])) + :opt-un [::network + ::wait-for])) (s/def ::init-options (s/keys :req-un [::csc/container] @@ -23,6 +30,7 @@ ::csc/env-vars ::csc/command ::network + ::wait-for ::csc/network-aliases])) (s/def ::create-options @@ -31,6 +39,7 @@ ::csc/env-vars ::csc/command ::network + ::wait-for ::csc/network-aliases])) (s/def ::create-network-options diff --git a/test/clj_test_containers/core_test.clj b/test/clj_test_containers/core_test.clj index dc3d277..b48f806 100644 --- a/test/clj_test_containers/core_test.clj +++ b/test/clj_test_containers/core_test.clj @@ -19,6 +19,20 @@ (is (nil? (:id stopped-container))) (is (nil? (:mapped-ports stopped-container))))) + (testing "Testing basic testcontainer generic image initialisation with wait for log message" + (let [container (sut/create {:image-name "postgres:12.2" + :exposed-ports [5432] + :env-vars {"POSTGRES_PASSWORD" "pw"} + :wait-for {:strategy :log :message "accept connections"}}) + initialized-container (sut/start! container) + stopped-container (sut/stop! container)] + (is (some? (:id initialized-container))) + (is (some? (:mapped-ports initialized-container))) + (is (some? (get (:mapped-ports initialized-container) 5432))) + (is (= (:wait-for-log-message initialized-container) ".*accept connections.*\\n")) + (is (nil? (:id stopped-container))) + (is (nil? (:mapped-ports stopped-container))))) + (testing "Testing basic testcontainer image creation from docker file" (let [container (sut/create-from-docker-file {:exposed-ports [80] :docker-file "test/resources/Dockerfile"})