         wk-val "initial-wk-value"]
 
     ;;; This transaction will succeed
-    (wc (r/set k  k-val)
-        (r/set wk wk-val))
+    (wcar (car/set k  k-val)
+          (car/set wk wk-val))
     (is (= ["PONG" "OK"]
-           (wc (r/atomically
-                []
-                (let [wk-val (wc (r/get wk))]
-                  (r/ping)
-                  (r/set k wk-val))))))
-    (is (= wk-val (wc (r/get k))))
+           (wcar (car/atomically
+                  []
+                  (let [wk-val (wcar (car/get wk))]
+                    (car/ping)
+                    (car/set k wk-val))))))
+    (is (= wk-val (wcar (car/get k))))
 
     ;;; This transaction will fail
-    (wc (r/set k  k-val)
-        (r/set wk wk-val))
+    (wcar (car/set k  k-val)
+          (car/set wk wk-val))
     (is (= []
-           (wc (r/atomically
-                [wk]
-                (wc (r/set wk "CHANGE!")) ; Will break watch
-                (r/ping)))))
-    (is (= k-val (wc (r/get k))))))
+           (wcar (car/atomically
+                  [wk]
+                  (wcar (car/set wk "CHANGE!")) ; Will break watch
+                  (car/ping)))))
+    (is (= k-val (wcar (car/get k))))))
 
 (clean-up!) ; Leave with a fresh db
  (let [k1   (test-key "stress-data")
        k2   (test-key "stress-data-hash")
        data (dissoc nippy/stress-data :bytes)]
    (wc (r/set k1 data))
    (is (= data (wc (r/get k1))))

    (wc (r/hmset k2 "field1" data "field2" "just a string"))
    (is (= data (wc (r/hget k2 "field1"))))
    (is (= "just a string" (wc (r/hget k2 "field2"))))))

(deftest test-preserved-values
  (let [num-key      (test-key "num-key")
        preserve-key (test-key "preserve-key")]
    (wc (r/set num-key 10)
        (r/set preserve-key (r/preserve 10)))
    (is (= (wc (r/get num-key))      "10"))
    (is (= (wc (r/get preserve-key)) 10))))

(deftest test-binary-safety
  (let [k (test-key "binary-safety")
        ba (byte-array [(byte 3) (byte 1) (byte 4)])]
    (wc (r/set k ba))
    (is (= [ba 3]) (wc (r/get k)))))

(deftest test-nulls
  (let [k (test-key "nulls")]
    (wc (r/set k nil))
    (is (= nil (wc (r/get k))))
    (wc (r/set k ""))
    (is (= "" (wc (r/get k))))
    (wc (r/set k " "))
    (is (= " " (wc (r/get k))))
    (wc (r/set k (byte-array 0)))
    (is (= 0 (second (wc (r/get k)))))
    (wc (r/set k (.getBytes "\u0000" "UTF-8")))
    (is (= 1 (second (wc (r/get k)))))
    (wc (r/set k "Foobar\u0000"))
    (is (= "Foobar\u0000" (wc (r/get k))))
    (is (thrown? Exception (wc (r/set k "\u0000Foobar"))))))

(deftest test-big-responses
  (let [k (test-key "big-list")
        n 250000]
    (wc (dorun (repeatedly n (fn [] (r/rpush k "value")))))
    (is (= (repeat n "value") (wc (r/lrange k 0 -1))))))

(deftest test-lua
  (when (redis-version-sufficient? "2.6.0")
    (let [k (test-key "script")
          script "return redis.call('set',KEYS[1],'script-value')"
          script-hash (r/hash-script script)]
      (wc (r/script-load script))
      (wc (r/evalsha script-hash 1 k))
      (is (= "script-value" (wc (r/get k))))
      (is (= ["key1" "key2" "arg1" "arg2"]
             (wc (r/eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}"
                         2 "key1" "key2" "arg1" "arg2")))))))

(deftest test-reply-parsing
  (let [k (test-key "reply-parsing")]
    (wc (r/set k [:a :A :b :B :c :C :d :D]))
    (is (= ["PONG" {:a :A :b :B :c :C :d :D} "PONG" "PONG"]
           (wc (r/ping)
               (r/with-parser #(apply hash-map %) (r/get k))
               (r/ping)
               (r/ping))))))

(deftest test-transactions
  (let [k      (test-key "atomic")


;;;; Setup

(def p (car/make-conn-pool))
(def s (car/make-conn-spec))
(defmacro wcar [& body] `(car/with-conn p s ~@body))

(defn redis-version-sufficient?
  [minimum-version]
  (utils/version-sufficient? (get (wcar (car/info*)) "redis_version")
                             minimum-version))

(defn test-key [key] (str "carmine:temp:test:" key))
(defn clean-up!
  []
  (let [test-keys (wcar (car/keys (test-key "*")))]
    (when (seq test-keys)
      (wcar (apply car/del test-keys)))))

;;;; Tests

(clean-up!) ; Start with a fresh db

(deftest test-echo
  (is (= "Message" (wcar (car/echo "Message"))))
  (is (= "PONG"    (wcar (car/ping)))))

(deftest test-exists
  (let [k (test-key "singularity")]
    (is (= 0 (wcar (car/exists k))))
    (wcar (car/set k "exists"))
    (is (= 1 (wcar (car/exists k))))))

(deftest test-set-get
  (let [k (test-key "server:name")]
    (is (= "OK" (wcar (car/set k "fido"))))
    (is (= "fido" (wcar (car/get k))))
    (is (= 15 (wcar (car/append k " [shutdown]"))))
    (is (= "fido [shutdown]" (wcar (car/getset k "fido [running]"))))
    (is (= "running" (wcar (car/getrange k 6 12)))))
  (let [k (test-key "mykey")]
    (wcar (car/setbit k 7 1))
    (is (= 1 (wcar (car/getbit k 7)))))
  (let [k (test-key "multiline")]
    (is (= "OK" (wcar (car/set k "Redis\r\nDemo"))))
    (is (= "Redis\r\nDemo" (wcar (car/get k))))))

(deftest test-incr-decr
  (let [k (test-key "connections")]
    (wcar (car/set k 10))
    (is (= 11 (wcar (car/incr k))))
    (is (= 20 (wcar (car/incrby k 9))))
    (is (= 19 (wcar (car/decr k))))
    (is (= 10 (wcar (car/decrby k 9))))))

(deftest test-del
  (let [k (test-key "something")]
    (wcar (car/set k "foo"))
    (is (= 1 (wcar (car/del k))))))

(deftest test-expiry
  (let [k (test-key "resource:lock")]
    (wcar (car/set k "Redis Demo"))
    (is (= -1 (wcar (car/ttl k))))
    (is (= 1 (wcar (car/expire k 120))))
    (is (< 0 (wcar (car/ttl k))))))

(deftest test-lists
  (let [k (test-key "friends")]
    (wcar (car/rpush k "Tom"))
    (wcar (car/rpush k "Bob"))
    (wcar (car/lpush k "Sam"))
    (is (= ["Sam" "Tom" "Bob"]
           (wcar (car/lrange k 0 -1))))
    (is (= ["Sam" "Tom"]
           (wcar (car/lrange k 0 1))))
    (is (= ["Sam" "Tom" "Bob"]
           (wcar (car/lrange k 0 2))))
    (is (= 3 (wcar (car/llen k))))
    (is (= "Sam" (wcar (car/lpop k))))
    (is (= "Bob" (wcar (car/rpop k))))
    (is (= 1 (wcar (car/llen k))))
    (is (= ["Tom"] (wcar (car/lrange k 0 -1))))
    (wcar (car/del k))))

(deftest test-non-ascii-params
  (let [k (test-key "spanish")]
    (is (= "OK" (wcar (car/set k "year->año"))))
    (is (= "year->año" (wcar (car/get k))))))

(deftest test-error-handling
  (let [k (test-key "str-field")]
    (wcar (car/set k "str-value"))
    (is (thrown? Exception (wcar (car/incr k))))
    (is (some #(instance? Exception %)
              (wcar (car/ping) (car/incr k) (car/ping))))))

(deftest test-commands-as-real-functions
  (is (= nil (wcar "This is a malformed request")))
  (is (= "PONG" (wcar (car/ping) "This is a malformed request")))
  (is (= ["PONG" "PONG" "PONG"] (wcar (doall (repeatedly 3 car/ping)))))
  (is (= ["A" "B" "C"] (wcar (doall (map car/echo ["A" "B" "C"]))))))

(deftest test-composition
  (let [out-k (test-key "outside-key")
        in-k  (test-key "inside-key")]
    (wcar (car/set in-k  "inside value")
          (car/set out-k in-k))
    (is (= "inside value" (wcar (car/get (last (wcar (car/ping) (car/get out-k)))))))))

(deftest test-parallelism
  (let [k (test-key "parallel-key")]
    (wcar (car/set k 0))
    (->> (fn [] (future (dotimes [n 100] (wcar (car/incr k)))))
         (repeatedly 100) ; No. of parallel clients
         (doall)
         (map deref)
         (dorun))
    (is (= (wcar (car/get k)) "10000"))))

(deftest test-hashes
  (let [k (test-key "myhash")]
    (wcar (car/hset k "field1" "value1"))
    (is (= "value1" (wcar (car/hget k "field1"))))
    (wcar (car/hsetnx k "field1" "newvalue"))
    (is (= "value1" (wcar (car/hget k "field1"))))
    (is (= 1 (wcar (car/hexists k "field1"))))
    (is (= ["field1" "value1"] (wcar (car/hgetall k))))
    (wcar (car/hset k "field2" 1))
    (is (= 3 (wcar (car/hincrby k "field2" 2))))
    (is (= ["field1" "field2"] (wcar (car/hkeys k))))
    (is (= ["value1" "3"] (wcar (car/hvals k))))
    (is (= 2 (wcar (car/hlen k))))
    (wcar (car/hdel k "field1"))
    (is (= 0 (wcar (car/hexists k "field1"))))))

(deftest test-sets
  (let [k1 (test-key "superpowers")
        k2 (test-key "birdpowers")]
    (wcar (car/sadd k1 "flight"))
    (wcar (car/sadd k1 "x-ray vision"))
    (wcar (car/sadd k1 "reflexes"))
    (wcar (car/srem k1 "reflexes"))
    (is (= 1 (wcar (car/sismember k1 "flight"))))
    (is (= 0 (wcar (car/sismember k1 "reflexes"))))
    (wcar (car/sadd k2 "pecking"))
    (wcar (car/sadd k2 "flight"))
    (is (= (set ["flight" "pecking" "x-ray vision"])
           (set (wcar (car/sunion k1 k2)))))))

(deftest test-sorted-sets
  (let [k1 (test-key "hackers")
        k2 (test-key "slackers")
        k1-U-k2 (test-key "hackersnslackers")
        k1-I-k2 (test-key "hackerslackers")]
    (wcar (car/zadd k1 "1940" "Alan Kay"))
    (wcar (car/zadd k1 "1953" "Richard Stallman"))
    (wcar (car/zadd k1 "1965" "Yukihiro Matsumoto"))
    (wcar (car/zadd k1 "1916" "Claude Shannon"))
    (wcar (car/zadd k1 "1969" "Linus Torvalds"))
    (wcar (car/zadd k1 "1912" "Alan Turing"))
    (wcar (car/zadd k1 "1972" "Dade Murphy"))
    (wcar (car/zadd k1 "1970" "Emmanuel Goldstein"))
    (wcar (car/zadd k2 "1968" "Pauly Shore"))
    (wcar (car/zadd k2 "1972" "Dade Murphy"))
    (wcar (car/zadd k2 "1970" "Emmanuel Goldstein"))
    (wcar (car/zadd k2 "1966" "Adam Sandler"))
    (wcar (car/zadd k2 "1962" "Ferris Beuler"))
    (wcar (car/zadd k2 "1871" "Theodore Dreiser"))
    (wcar (car/zunionstore* k1-U-k2 [k1 k2]))
    (wcar (car/zinterstore* k1-I-k2 [k1 k2]))
    (is (= ["Alan Kay" "Richard Stallman" "Yukihiro Matsumoto"]
           (wcar (car/zrange k1 2 4))))
    (is (= ["Claude Shannon" "Alan Kay" "Richard Stallman" "Ferris Beuler"]
           (wcar (car/zrange k1-U-k2 2 5))))
    (is (= ["Emmanuel Goldstein" "Dade Murphy"]
           (wcar (car/zrange k1-I-k2 0 1))))))

(deftest test-pipeline
  (let [k1 (test-key "children")
        k2 (test-key "favorite:child")]
    (wcar (car/rpush k1 "A")
          (car/rpush k1 "B")
          (car/rpush k1 "C"))
    (wcar (car/set k2 "B"))
    (is (= ["B" "B"] (wcar (car/get k2)
                           (car/get k2))))
    (is (= ["B" ["A" "B" "C"] "B"]
           (wcar (car/get k2)
                 (car/lrange k1 0 3)
                 (car/get k2))))))

(deftest test-pubsub
  (let [received (atom [])
        listener (car/with-new-pubsub-listener
                   s {"ps-foo" #(swap! received conj %)}
                   (car/subscribe "ps-foo"))]

    (wcar (car/publish "ps-foo" "one")
          (car/publish "ps-foo" "two")
          (car/publish "ps-foo" "three"))
    (Thread/sleep 500)
    (car/close-listener listener)
    (is (= @received [["subscribe" "ps-foo" 1]
                      ["message"   "ps-foo" "one"]
                      ["message"   "ps-foo" "two"]
                      ["message"   "ps-foo" "three"]])))

  (let [received (atom [])
        listener (car/with-new-pubsub-listener
                   s {"ps-foo" #(swap! received conj %)
                      "ps-baz" #(swap! received conj %)}
                   (car/subscribe "ps-foo" "ps-baz"))]
    (wcar (car/publish "ps-foo" "one")
          (car/publish "ps-bar" "two")
          (car/publish "ps-baz" "three"))
    (Thread/sleep 500)
    (car/close-listener listener)
    (is (= @received [["subscribe" "ps-foo" 1]
                      ["subscribe" "ps-baz" 2]
                      ["message"   "ps-foo" "one"]
                      ["message"   "ps-baz" "three"]])))

  (let [received (atom [])
        listener (car/with-new-pubsub-listener
                   s {"ps-*"   #(swap! received conj %)
                      "ps-foo" #(swap! received conj %)})]
    (car/with-open-listener listener
      (car/psubscribe "ps-*")
      (car/subscribe  "ps-foo"))
    (wcar (car/publish "ps-foo" "one")
          (car/publish "ps-bar" "two")
          (car/publish "ps-baz" "three"))
    (Thread/sleep 500)
    (car/with-open-listener listener
      (car/unsubscribe "ps-foo"))
    (Thread/sleep 500)
    (wcar (car/publish "ps-foo" "four")
          (car/publish "ps-baz" "five"))
    (Thread/sleep 500)
    (car/close-listener listener)
    (is (= @received [["psubscribe"  "ps-*"   1]
                      ["subscribe"   "ps-foo" 2]
                      ["message"     "ps-foo" "one"]
