Skip to content

Commit f6afa3b

Browse files
committed
store tests
1 parent c1d55d9 commit f6afa3b

File tree

10 files changed

+310
-1
lines changed

10 files changed

+310
-1
lines changed

README.adoc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,33 @@ message count per poll execution may be specified by `max.poll.records` field of
121121
$ lein install
122122
----
123123

124+
== Development and Testing
125+
126+
The project includes a test suite to verify functionality.
127+
128+
[source,text]
129+
----
130+
$ lein with-profile dev test
131+
----
132+
133+
For test coverage reports:
134+
135+
[source,text]
136+
----
137+
$ lein with-profile dev cloverage
138+
----
139+
140+
=== Integration Tests
141+
142+
The project includes integration tests that require a running Kafka instance. By default, these tests are skipped. To run them:
143+
144+
[source,clojure]
145+
----
146+
(binding [clj-kafka-x.integration-test/*run-integration-tests* true
147+
clj-kafka-x.integration-test/*kafka-bootstrap-servers* "localhost:9092"]
148+
(clj-kafka-x.integration-test/run-integration-tests))
149+
----
150+
124151
== License
125152

126153
Copyright © 2016-2025

profiles.clj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
{:dev {:dependencies [[midje "1.10.10"]]}
1+
{:dev {:dependencies [[midje "1.10.10"]
2+
[org.slf4j/slf4j-simple "2.0.12"]
3+
[org.mockito/mockito-core "5.11.0"]]
4+
:test-paths ["test"]
5+
:plugins [[lein-cloverage "1.2.4"]]}
26
:docs {:plugins [[lein-codox "0.10.8"]
37
[org.timmc/nephila "0.3.0"]]}
48
:provided {:dependencies [[org.clojure/clojure "1.12.0"]]}

test/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# clj-kafka-x tests
2+
3+
This directory contains tests for the clj-kafka-x library.
4+
5+
## Running Tests
6+
7+
To run all tests:
8+
9+
```
10+
lein with-profile dev test
11+
```
12+
13+
To run specific tests:
14+
15+
```
16+
lein with-profile dev test clj-kafka-x.producer-test
17+
lein with-profile dev test clj-kafka-x.consumers.simple-test
18+
lein with-profile dev test clj-kafka-x.data-test
19+
lein with-profile dev test clj-kafka-x.impl.helpers-test
20+
```
21+
22+
## Test Coverage
23+
24+
To generate test coverage reports:
25+
26+
```
27+
lein with-profile dev cloverage
28+
```
29+
30+
The coverage report will be generated in `target/coverage/`.
31+
32+
## Test Structure
33+
34+
- `test_helpers.clj`: Contains helper functions for testing, including mock producer and consumer setup
35+
- `producer_test.clj`: Tests for the producer functionality
36+
- `consumers/simple_test.clj`: Tests for the consumer functionality
37+
- `data_test.clj`: Tests for data conversion functionality
38+
- `impl/helpers_test.clj`: Tests for helper functions
39+
- `test_runner.clj`: A standalone test runner
40+
41+
## Notes
42+
43+
The tests use mock Kafka producers and consumers to avoid requiring a running Kafka instance. This allows for faster and more reliable tests.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(ns clj-kafka-x.consumers.simple-test
2+
(:require [clojure.test :refer :all]
3+
[clj-kafka-x.consumers.simple :as kc])
4+
(:import [org.apache.kafka.common.serialization StringDeserializer ByteArrayDeserializer]))
5+
6+
(deftest test-deserializers
7+
(testing "string-deserializer creates a StringDeserializer"
8+
(is (instance? StringDeserializer (kc/string-deserializer))))
9+
10+
(testing "byte-array-deserializer creates a ByteArrayDeserializer"
11+
(is (instance? ByteArrayDeserializer (kc/byte-array-deserializer)))))

test/clj_kafka_x/data_test.clj

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
(ns clj-kafka-x.data-test
2+
(:require [clojure.test :refer :all]
3+
[clj-kafka-x.data :refer :all])
4+
(:import [org.apache.kafka.common TopicPartition]
5+
[org.apache.kafka.clients.consumer OffsetAndMetadata]
6+
[java.util Properties]))
7+
8+
(deftest test-map->properties
9+
(testing "map->properties converts map to Properties"
10+
(let [m {"key1" "value1" "key2" "value2"}
11+
props (map->properties m)]
12+
(is (instance? Properties props))
13+
(is (= "value1" (.getProperty props "key1")))
14+
(is (= "value2" (.getProperty props "key2"))))))
15+
16+
(deftest test-map->topic-partition
17+
(testing "map->topic-partition converts map to TopicPartition"
18+
(let [m {:topic "test-topic" :partition 1}
19+
tp (map->topic-partition m)]
20+
(is (instance? TopicPartition tp))
21+
(is (= "test-topic" (.topic tp)))
22+
(is (= 1 (.partition tp)))))
23+
24+
(testing "map->topic-partition throws exception on invalid input"
25+
(is (thrown? clojure.lang.ExceptionInfo (map->topic-partition {:topic "test-topic"})))
26+
(is (thrown? clojure.lang.ExceptionInfo (map->topic-partition {:partition 1})))))
27+
28+
(deftest test-map->offset-metadata
29+
(testing "map->offset-metadata converts map to OffsetAndMetadata"
30+
(let [m {:offset 100 :metadata "test-metadata"}
31+
om (map->offset-metadata m)]
32+
(is (instance? OffsetAndMetadata om))
33+
(is (= 100 (.offset om)))
34+
(is (= "test-metadata" (.metadata om)))))
35+
36+
(testing "map->offset-metadata throws exception on invalid input"
37+
(is (thrown? clojure.lang.ExceptionInfo (map->offset-metadata {:offset 100})))
38+
(is (thrown? clojure.lang.ExceptionInfo (map->offset-metadata {:metadata "test"})))))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(ns clj-kafka-x.impl.helpers-test
2+
(:require [clojure.test :refer :all]
3+
[clj-kafka-x.impl.helpers :refer :all])
4+
(:import [org.apache.kafka.common.config ConfigDef ConfigDef$Type]
5+
[org.apache.kafka.clients.producer ProducerConfig]))
6+
7+
(deftest test-coerce-config
8+
(testing "coerce-config passes through string values"
9+
(let [config-def (ProducerConfig/configDef)
10+
config {"bootstrap.servers" "localhost:9092"
11+
"key.serializer" "org.apache.kafka.common.serialization.StringSerializer"
12+
"value.serializer" "org.apache.kafka.common.serialization.StringSerializer"}
13+
coerced (coerce-config config-def config)]
14+
15+
(is (= "localhost:9092" (get coerced "bootstrap.servers")))
16+
(is (= "org.apache.kafka.common.serialization.StringSerializer" (get coerced "key.serializer")))
17+
(is (= "org.apache.kafka.common.serialization.StringSerializer" (get coerced "value.serializer"))))))

test/clj_kafka_x/integration_test.clj

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
(ns clj-kafka-x.integration-test
2+
(:require [clojure.test :refer :all]
3+
[clj-kafka-x.producer :as kp]
4+
[clj-kafka-x.consumers.simple :as kc])
5+
(:import [java.util UUID]))
6+
7+
(def ^:dynamic *run-integration-tests* false)
8+
(def ^:dynamic *kafka-bootstrap-servers* "localhost:9092")
9+
(def ^:dynamic *test-topic* "clj-kafka-x-test-topic")
10+
11+
(defn integration-fixture [f]
12+
(if *run-integration-tests*
13+
(try
14+
(println "Running integration tests with Kafka at" *kafka-bootstrap-servers*)
15+
(f)
16+
(catch Exception e
17+
(println "Error in integration tests:" (.getMessage e))
18+
(throw e)))
19+
(println "Skipping integration tests. Set *run-integration-tests* to true to run them.")))
20+
21+
(use-fixtures :once integration-fixture)
22+
23+
(deftest ^:integration test-produce-consume-cycle
24+
(testing "Full produce-consume cycle with real Kafka"
25+
(when *run-integration-tests*
26+
(let [test-id (str (UUID/randomUUID))
27+
producer-config {"bootstrap.servers" *kafka-bootstrap-servers*}
28+
consumer-config {"bootstrap.servers" *kafka-bootstrap-servers*
29+
"group.id" (str "test-group-" test-id)
30+
"auto.offset.reset" "earliest"}
31+
test-key "test-key"
32+
test-value (str "test-value-" test-id)]
33+
34+
;; Produce a message
35+
(with-open [producer (kp/producer producer-config
36+
(kp/string-serializer)
37+
(kp/string-serializer))]
38+
(let [record (kp/record *test-topic* test-key test-value)
39+
result @(kp/send producer record)]
40+
(is (= *test-topic* (:topic result)))
41+
(is (number? (:offset result)))))
42+
43+
;; Consume the message
44+
(with-open [consumer (kc/consumer consumer-config
45+
(kc/string-deserializer)
46+
(kc/string-deserializer))]
47+
(kc/subscribe consumer *test-topic*)
48+
49+
;; Poll for messages (with retry)
50+
(let [poll-with-timeout (fn []
51+
(let [msgs (kc/messages consumer :timeout 5000)]
52+
(if (seq msgs)
53+
msgs
54+
(do
55+
(Thread/sleep 1000)
56+
(kc/messages consumer :timeout 5000)))))
57+
messages (poll-with-timeout)]
58+
59+
(is (seq messages) "Should have received at least one message")
60+
61+
;; Find our test message
62+
(let [test-message (first (filter #(= test-key (:key %)) messages))]
63+
(is test-message "Should have found the test message")
64+
(when test-message
65+
(is (= test-value (:value test-message)))
66+
(is (= *test-topic* (:topic test-message)))))))))))
67+
68+
(defn run-integration-tests []
69+
(binding [*run-integration-tests* true]
70+
(run-tests 'clj-kafka-x.integration-test)))

test/clj_kafka_x/producer_test.clj

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
(ns clj-kafka-x.producer-test
2+
(:require [clojure.test :refer :all]
3+
[clj-kafka-x.producer :as kp])
4+
(:import [org.apache.kafka.common.serialization StringSerializer ByteArraySerializer]
5+
[org.apache.kafka.clients.producer ProducerRecord]))
6+
7+
(deftest test-serializers
8+
(testing "string-serializer creates a StringSerializer"
9+
(is (instance? StringSerializer (kp/string-serializer))))
10+
11+
(testing "byte-array-serializer creates a ByteArraySerializer"
12+
(is (instance? ByteArraySerializer (kp/byte-array-serializer)))))
13+
14+
(deftest test-record-creation
15+
(testing "record creates ProducerRecord with only topic and value"
16+
(let [record (kp/record "test-topic" "test-value")]
17+
(is (instance? ProducerRecord record))
18+
(is (= "test-topic" (.topic record)))
19+
(is (= "test-value" (.value record)))
20+
(is (nil? (.key record)))))
21+
22+
(testing "record creates ProducerRecord with topic, key, and value"
23+
(let [record (kp/record "test-topic" "test-key" "test-value")]
24+
(is (instance? ProducerRecord record))
25+
(is (= "test-topic" (.topic record)))
26+
(is (= "test-key" (.key record)))
27+
(is (= "test-value" (.value record)))))
28+
29+
(testing "record creates ProducerRecord with topic, partition, key, and value"
30+
(let [record (kp/record "test-topic" (int 1) "test-key" "test-value")]
31+
(is (instance? ProducerRecord record))
32+
(is (= "test-topic" (.topic record)))
33+
(is (= 1 (.partition record)))
34+
(is (= "test-key" (.key record)))
35+
(is (= "test-value" (.value record))))))

test/clj_kafka_x/test_helpers.clj

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
(ns clj-kafka-x.test-helpers
2+
(:require [clojure.test :refer :all]
3+
[clj-kafka-x.producer :as kp]
4+
[clj-kafka-x.consumers.simple :as kc])
5+
(:import [org.apache.kafka.clients.producer MockProducer]
6+
[org.apache.kafka.clients.consumer MockConsumer OffsetResetStrategy]
7+
[org.apache.kafka.common.serialization StringSerializer StringDeserializer]
8+
[org.apache.kafka.common TopicPartition]
9+
[org.apache.kafka.clients.producer ProducerConfig]))
10+
11+
;; We need to explicitly import the inner class because of a limitation in Clojure's interop
12+
(def earliest-offset-reset-strategy (OffsetResetStrategy/EARLIEST))
13+
14+
(defn create-mock-producer
15+
"Creates a MockProducer for testing"
16+
[]
17+
;; Using constructor with 3 args: autoComplete, keySerializer, valueSerializer
18+
(doto (MockProducer.)
19+
(.init true
20+
(StringSerializer.)
21+
(StringSerializer.))))
22+
23+
(defn create-mock-consumer
24+
"Creates a MockConsumer for testing"
25+
[]
26+
(MockConsumer. earliest-offset-reset-strategy))
27+
28+
(defn setup-consumer-assignment
29+
"Sets up a mock consumer with assignments for testing"
30+
[consumer topic partitions]
31+
(let [topic-partitions (map #(TopicPartition. topic %) partitions)]
32+
(.assign consumer topic-partitions)
33+
(.updateBeginningOffsets consumer
34+
(into {} (map #(vector % 0) topic-partitions)))
35+
consumer))
36+
37+
(defn add-consumer-record
38+
"Adds a record to the mock consumer"
39+
[consumer topic partition offset key value]
40+
(let [tp (TopicPartition. topic partition)]
41+
(.addRecord consumer (org.apache.kafka.clients.consumer.ConsumerRecord.
42+
topic
43+
partition
44+
offset
45+
key
46+
value))
47+
consumer))

test/clj_kafka_x/test_runner.clj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(ns clj-kafka-x.test-runner
2+
(:require [clojure.test :refer [run-tests successful?]]
3+
[clj-kafka-x.producer-test]
4+
[clj-kafka-x.data-test]
5+
[clj-kafka-x.impl.helpers-test]
6+
[clj-kafka-x.consumers.simple-test])
7+
(:gen-class))
8+
9+
(defn run-all-tests []
10+
(let [results (run-tests 'clj-kafka-x.producer-test
11+
'clj-kafka-x.data-test
12+
'clj-kafka-x.impl.helpers-test
13+
'clj-kafka-x.consumers.simple-test)]
14+
(System/exit (if (successful? results) 0 1))))
15+
16+
(defn -main [& args]
17+
(run-all-tests))

0 commit comments

Comments
 (0)