(s/def ::a nat-int?)
(s/def ::data
(s/keys :req [::a]))
(deftest a-test
(let [data (gen/sample (s/gen ::data) 200)
out-chan (a/chan 10)
in-chan (a/chan 10)
f (fn [{::keys [a]}]
(when (odd? a)
a))
data-filtered (into [] (keep f) data)]
(a/pipeline 4
out-chan
(keep f)
in-chan)
(a/go (doseq [d data]
(a/>! in-chan d)))
(a/go-loop [i 0]
(println (a/<! out-chan))
(is (= (nth (reverse data-filtered) i)
(a/<! out-chan)))
(recur (inc i)))))
in this case, this test prints and runyou are spinning off logical threads (go blocks) but not waiting around for them, which will break things a lot of the time when running tests
running the test a-test expects the testing to be complete when the function of the test returns
imagine every go block is a use of future
channels are mutable, you are taking something out of the channel to print it, then taking something out of the channel to compare it to something in data-filtered
also, the reversing isn't necessary...
(deftest a-test
(let [data (gen/sample (s/gen ::data) 200)
out-chan (a/chan 10)
in-chan (a/chan 10)
f (fn [{::keys [a]}]
(when (odd? a)
a))
data-filtered (into [] (keep f) data)]
(a/pipeline 4
out-chan
(keep f)
in-chan)
(a/go (doseq [d data]
(a/>! in-chan d)))
(a/go-loop [i 0]
(when-let [v (a/<! out-chan)]
(println v)
(is (= (nth data-filtered i) v))
(recur (inc i))))))
this "passes" (in the sense that all the equalities seem to check out), but like hired said, the is calls happen asynchronously to the deftest, so the test technically passes regardless of what happens in the go-loop bodyif we make the loop synchronous, it "works" from a clojure.test standpoint... whether it does what's desired or not is less clear. I also made in-chan a chan from the data at the beginning, which isn't necessarily relevant, but just a bit shorter:
(deftest a-test
(let [data (gen/sample (s/gen ::data) 200)
out-chan (a/chan 10)
in-chan (a/to-chan! data)
f (fn [{::keys [a]}]
(when (odd? a)
a))
data-filtered (into [] (keep f) data)]
(a/pipeline 4
out-chan
(keep f)
in-chan)
(loop [i 0]
(when-let [v (a/<!! out-chan)]
(println v)
(is (= (nth data-filtered i) v))
(recur (inc i))))))
there is nothing that guarantees an ordering between the execution of code in the go blocks and the completion of the test, so technically it is a race, the go blocks just run fast enough in this case that usually they complete before the test does
I guess another option would also be that since the go-loop returns a channel, do a blocking take from that channel, and as long as the go-loop eventually returns (which can be returning nil from the when-let), that should bridge the synch of the deftest.
it fails, but it prints and run
is there any way to make this test pass ?