diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 740e2b7..87fea9f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,16 +4,6 @@ jobs: test: runs-on: ubuntu-22.04 timeout-minutes: 5 - services: - aerospike-test: - image: aerospike:ee-6.2.0.3 - ports: - - 3000:3000 - - 3001:3001 - - 3002:3002 - - 3003:3003 - env: - AEROSPIKE_HOST: localhost steps: - name: Checkout uses: actions/checkout@v3 diff --git a/project.clj b/project.clj index e1ceb13..014c957 100644 --- a/project.clj +++ b/project.clj @@ -20,6 +20,7 @@ [lein-ancient "0.6.15"] [lein-eftest "0.5.9"]] :dependencies [[org.clojure/clojure "1.11.1"] + [clj-test-containers "0.7.4"] [criterium "0.4.6"] [cheshire "5.11.0"] [com.fasterxml.jackson.core/jackson-databind "2.11.2"] diff --git a/src/main/clojure/aerospike_clj/client.clj b/src/main/clojure/aerospike_clj/client.clj index bb96195..6c61cb1 100644 --- a/src/main/clojure/aerospike_clj/client.clj +++ b/src/main/clojure/aerospike_clj/client.clj @@ -19,7 +19,7 @@ [com.aerospike.client.policy Policy BatchPolicy ClientPolicy RecordExistsAction WritePolicy ScanPolicy InfoPolicy] - [com.aerospike.client Key Host BatchRecord Record] + [com.aerospike.client Key Host BatchRecord] [aerospike_clj.listeners AsyncExistsListener AsyncDeleteListener AsyncWriteListener AsyncInfoListener AsyncRecordListener AsyncRecordSequenceListener AsyncBatchListListener AsyncExistsArrayListener AsyncBatchOperateListListener] diff --git a/test/aerospike_clj/integration/aerospike_setup.clj b/test/aerospike_clj/integration/aerospike_setup.clj new file mode 100644 index 0000000..7a66172 --- /dev/null +++ b/test/aerospike_clj/integration/aerospike_setup.clj @@ -0,0 +1,31 @@ +(ns aerospike-clj.integration.aerospike-setup + (:require [clj-test-containers.core :as tc])) + +(def ^:private ^:const container-port 3000) +(def ^:private container (atom nil)) + +(defn get-host-and-port [] + (format "%s:%s" (:host @container) (get (:mapped-ports @container) container-port))) + +(defn- start-container [] + (->> {:image-name "aerospike:ee-6.2.0.3" + :exposed-ports [container-port] + :wait-for {:wait-strategy :log + :message "objects: all 0 master 0 prole 0 non-replica 0" + :times 1 + :startup-timeout 15}} + tc/create + tc/start! + (reset! container))) + +(defn- stop! [] + (tc/stop! @container) + (reset! container nil?)) + +(defn with-aerospike [test-fn] + (start-container) + (try + (test-fn) + (finally + (stop!)))) + diff --git a/test/aerospike_clj/integration/integration_test.clj b/test/aerospike_clj/integration/integration_test.clj index 1659d64..3dcd417 100644 --- a/test/aerospike_clj/integration/integration_test.clj +++ b/test/aerospike_clj/integration/integration_test.clj @@ -1,18 +1,15 @@ (ns ^{:author "Ido Barkan" - :integration true - :doc "Integration tests. Requires a local Aerospike instance. - To run instances locally inside docker containers: - $ sudo docker pull aerospike - $ sudo docker run -d --name aerospike -p 3000:3000 -p 3001:3001 -p 3002:3002 -p 3003:3003 aerospike"} - aerospike-clj.integration-test + :integration true} + aerospike-clj.integration.integration-test (:require [clojure.test :refer [deftest testing is use-fixtures]] + [cheshire.core :as json] + [aerospike-clj.integration.aerospike-setup :as as-setup] [aerospike-clj.client :as client] [aerospike-clj.protocols :as pt] [aerospike-clj.policy :as policy] [aerospike-clj.key :as as-key] - [cheshire.core :as json] [aerospike-clj.utils :as utils]) - (:import [com.aerospike.client Value AerospikeClient BatchRecord BatchWrite Key Value$LongValue Operation Operation$Type Bin] + (:import [com.aerospike.client Value AerospikeClient BatchWrite Operation Bin] [com.aerospike.client.cdt ListOperation ListPolicy ListOrder ListWriteFlags ListReturnType MapOperation MapPolicy MapOrder MapWriteFlags MapReturnType CTX] [com.aerospike.client.policy ReadModeSC ReadModeAP Replica GenerationPolicy RecordExistsAction @@ -21,36 +18,39 @@ [java.util.concurrent ExecutionException] [clojure.lang PersistentArrayMap] [aerospike_clj.client SimpleAerospikeClient] - (com.aerospike.client.exp Exp Expression ExpOperation))) + (com.aerospike.client.exp Exp))) (def _set "set") (def _set2 "set2") (def as-namespace "test") (def ^:dynamic *c* nil) +(def ^:dynamic *as-hosts* nil) (def TTL 5) -(defn db-connection [test-fn] - (binding [*c* (client/init-simple-aerospike-client - ["localhost"] - as-namespace)] - (test-fn) - (pt/stop *c*))) +(defn with-db-connection [test-fn] + (let [as-hosts [(as-setup/get-host-and-port)]] + (binding [*c* (client/init-simple-aerospike-client + as-hosts + as-namespace) + *as-hosts* as-hosts] + (test-fn) + (pt/stop *c*)))) -(use-fixtures :once db-connection) +(use-fixtures :once as-setup/with-aerospike with-db-connection) (deftest client-creation - (let [c (client/init-simple-aerospike-client ["localhost"] "test")] + (let [c (client/init-simple-aerospike-client *as-hosts* as-namespace)] (is c) - (is (= ["localhost"] (.-hosts ^SimpleAerospikeClient c)))) + (is (= *as-hosts* (.-hosts ^SimpleAerospikeClient c)))) (letfn [(no-password? [ex] (let [conf (:conf (ex-data ex))] (and conf (not (contains? conf "password")))))] - (let [ex (is (thrown-with-msg? Exception #"unbounded delay queue" (client/init-simple-aerospike-client ["localhost"] "test" {"maxCommandsInProcess" 1})))] + (let [ex (is (thrown-with-msg? Exception #"unbounded delay queue" (client/init-simple-aerospike-client *as-hosts* as-namespace {"maxCommandsInProcess" 1})))] (is (no-password? ex))) (with-redefs [client/create-event-loops (constantly nil)] - (let [ex (is (thrown-with-msg? Exception #"event-loops" (client/init-simple-aerospike-client ["localhost"] "test")))] + (let [ex (is (thrown-with-msg? Exception #"event-loops" (client/init-simple-aerospike-client *as-hosts* as-namespace)))] (is (no-password? ex)))))) (deftest info @@ -582,7 +582,7 @@ (deftest configure-read-and-batch-policy (let [c (client/init-simple-aerospike-client - ["localhost"] "test" + *as-hosts* as-namespace {"readPolicyDefault" (policy/map->policy {"ReadModeAP" "ALL" "ReadModeSC" "LINEARIZE" "maxRetries" 1 @@ -632,7 +632,7 @@ (deftest configure-write-policy (let [c (client/init-simple-aerospike-client - ["localhost"] "test" + *as-hosts* as-namespace {"writePolicyDefault" (policy/map->write-policy {"CommitLevel" "COMMIT_MASTER" "durableDelete" true "expiration" 1000 @@ -653,7 +653,7 @@ (deftest configure-batch-write-policies (let [expression (Exp/build (Exp/ge (Exp/intBin "a") (Exp/intBin "b"))) c (client/init-simple-aerospike-client - ["localhost"] "test" + *as-hosts* as-namespace {"batchWritePolicyDefault" (policy/map->batch-write-policy {"CommitLevel" "COMMIT_MASTER" "durableDelete" true "expiration" 1000 diff --git a/test/aerospike_clj/integration/metrics_test.clj b/test/aerospike_clj/integration/metrics_test.clj index bd23311..8959bf2 100644 --- a/test/aerospike_clj/integration/metrics_test.clj +++ b/test/aerospike_clj/integration/metrics_test.clj @@ -1,12 +1,15 @@ (ns ^{:author "Ido Barkan" :integration true} - aerospike-clj.metrics-test - (:require [clojure.test :refer [deftest is]] + aerospike-clj.integration.metrics-test + (:require [clojure.test :refer [deftest is use-fixtures]] [aerospike-clj.client :as client] + [aerospike-clj.integration.aerospike-setup :as as-setup] [aerospike-clj.protocols :as pt])) +(use-fixtures :once as-setup/with-aerospike) + (deftest get-cluster-stats - (let [c (client/init-simple-aerospike-client ["localhost"] "test") + (let [c (client/init-simple-aerospike-client [(as-setup/get-host-and-port)] "test") loopback-v4 "127-0-0-1" loopback-v6 "0:0:0:0:0:0:0:1"] (is (or