I'm just starting to use mocks in racket and I want to test the following code:
(define (tables #:connector [postgresql-connect postgresql-connect]
#:list-tables [list-tables list-tables])
; connect to the db
(define pgc
(postgresql-connect #:user "app_user"
#:database "test_database"
#:password "something_secure"))
; find all the tables
(list-tables pgc))
So I have a couple test cases:
(module+ test
(require rackunit)
(require mock)
(require mock/rackunit)
(test-case "it returns a report structure"
(check-eq? (sniffer "not://a.url/test") "not://a.url/test"))
(test-case "it calls the db connector with the right arguments"
(define connector-mock (mock #:behavior postgresql-connect))
(sniffer "not://a.url/test" #:connector connector-mock)
(check-mock-called-with? connector-mock (arguments #:database "test_database"
#:password "something_secure"
#:user "app_user")))
(test-case "it compiles a list of tables to examine"
(define connector-mock (mock #:behavior postgresql-connect ))
(define list-tables-mock (mock #:behavior list-tables ))
(sniffer "not://a.url/test" #:connector connector-mock #:list-tables list-tables-mock)
(check-mock-called-with? list-tables-mock (arguments connector-mock))))
When I run the tests I get:
--------------------
it calls the db connector with the right arguments
; ERROR
tcp-connect: connection failed
hostname: localhost
port number: 5432
system error: Connection refused; errno=61
--------------------
--------------------
it compiles a list of tables to examine
; ERROR
tcp-connect: connection failed
hostname: localhost
port number: 5432
system error: Connection refused; errno=61
--------------------
This leads me to this. How do I tell the mocks to mimic postgresql-connect without calling the actual implementation?
When you use the #:behavior keyword, you're saying that the mock should actually call that function. You're passing postgresql-connect, so the mock actually tries to connect. You will need to pass a different function that doesn't actually do the connection but takes the same arguments, perhaps with define-opaque from the mock library.
This example from the mock documentation may be helpful.
Related
I would like to write tests for a Pedestal web-service.
If I have :
(defn pong
[request]
(ring-resp/response "pong"))
(defroutes routes[[["/" {:get pong}]]])
How would I write a test for that ?
(deftest alive-system
(testing "ping-pong route"
;; How do I test my route ?
;; If possible :
;; - I would like to have direct access to it
;; ie. no need to bind pedestal to a port would be nice
;; - The ability to omit some interceptors would be nice also,
;; as it would allow me to receive plain Clojure data structures
;; instead of, for instance, JSON which I would have to parse.
...)
Edit:
Here is what I tried :
(deftest alive-system
(testing "ping-pong route"
(let [response (my-other.ns/routes (mock/request :get "/ping"))]
(is (= (:status response) 200))
(is (= (:body response) "pong")))))
But I get an exception :
ERROR in (alive-system) (service_test.clj:13)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
So after asking on the issue I linked ohpaulez replied :
#nha - Thanks for using Pedestal! Sorry your question didn't get an
answer on StackOverflow - I don't think anyone monitors SO for
Pedestal questions. The best place to ask those kinds of questions is
on the mailing list.
Pedestal ships with its own utility for making requests directly to
the servlet (similar to ring/mock, although I've never used mock
myself) called response-for. The Pedestal Service template produces a
test automatically for you. Check out one of the samples for an
example.
Also note that said response-for doesn't yet support asynchronous responses (so my routes that uses asynchronous interceptors with core.async failed - I had to make them synchronous).
I'm checking if YeSQL may help in my Clojure project, but I cannot find any example of YeSQL using a connection pool.
does this mean that YeSQL creates a new connection to every statement?
I also found an example on how to use transactions using clojure.java.jdbc/with-db-transaction, but I feel it is outdated (I haven't tried yet).
does this mean that YeSQL depends on clojure.java.jdbc to commit/rollback control? in this case, shouldn't I just use clojure.java.jdbc alone, since YeSQL doesn't offer too much more (other than naming my queries and externalizing them)?
thanks in advance
YeSQL doesn't handle connections or connection pooling. You need to handle it externally and provide a connection instance to the query function.
As you can see from the YeSQL example from README:
; Define a database connection spec. (This is standard clojure.java.jdbc.)
(def db-spec {:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:subname "//localhost:5432/demo"
:user "me"})
; Use it standalone. Note that the first argument is the db-spec.
(users-by-country db-spec "GB")
;=> ({:count 58})
; Use it in a clojure.java.jdbc transaction.
(require '[clojure.java.jdbc :as jdbc])
(jdbc/with-db-transaction [connection db-spec]
{:limeys (users-by-country connection "GB")
:yanks (users-by-country connection "US")})
If you ask how to add connection pool handling you might check an example from Clojure Cookbook.
As for the transaction handling, YeSQL documentation is none, but source is quite easy to understand:
(defn- emit-query-fn
"Emit function to run a query.
- If the query name ends in `!` it will call `clojure.java.jdbc/execute!`,
- If the query name ends in `<!` it will call `clojure.java.jdbc/insert!`,
- otherwise `clojure.java.jdbc/query` will be used."
[{:keys [name docstring statement]}]
(let [split-query (split-at-parameters statement)
{:keys [query-args display-args function-args]} (split-query->args split-query)
jdbc-fn (cond
(= [\< \!] (take-last 2 name)) `insert-handler
(= \! (last name)) `execute-handler
:else `jdbc/query)]
`(def ~(fn-symbol (symbol name) docstring statement display-args)
(fn [db# ~#function-args]
(~jdbc-fn db#
(reassemble-query '~split-query
~query-args))))))
So it will just generate a function that will either call clojure.java.jdbc/execute! or clojure.java.jdbc/insert! with the generated query. You might need to refer to those functions' documentation for further details.
When doing transactions using YesQL, I wrap the YesQL calls in a clojure.java.jdbc/with-db-transation invocation, and pass the generated connection details in to the YesQL function call, which they'll use instead of the standard non-transaction connection if supplied. For example:
;; supply a name for the transaction connection, t-con, based on the existing db connection
(jdbc/with-db-transaction [t-con db-spec]
;; this is the yesql call with a second map specifying the transaction connection
(create-client-order<! {...} {:connection t-con}))
All wrapped YesQL calls using the {:connection t-con} map will be part of the same transaction.
I have a rabbitMQ connection that seems to be started at compile time (when I type lein compile) and then blocks the building of my project. Here are more details on the problem. Let us say this is the clojure file bla_test.clj
(import (com.rabbitmq.client ConnectionFactory Connection Channel QueueingConsumer))
;; And then we have to translate the equivalent java hello world program using
;; Clojure's excellent interop.
;; It feels very strange writing this sort of ceremony-oriented imperative code
;; in Clojure:
;; Make a connection factory on the local host
(def connection-factory
(doto (ConnectionFactory.)
(.setHost "localhost")))
;; and get it to make you a connection
(def connection (.newConnection connection-factory))
;; get that to make you a channel
(def channel (. connection createChannel))
;;HERE I WOULD LIKE TO USE THE SAME CONNECTION AND THE SAME CHANNEL INSTANCE AS OFTEN AS
;; I LIKE
(dotimes [ i 10 ]
(. channel basicPublish "" "hello" nil (. (format "Hello World! (%d)" i) getBytes)))
The clojure file above is part of a bigger clojure program that I build using lein. My problem is that when I compile with "lein compile", a connection is done because of the line (def connection (.newConnection connection-factory)) and then the compilation is stopped! How can I avoid this? Is there a way to compile without building connection? How can I manage to use the same instance of channel over several calls coming from external components?
Any help would be appreciated.
Regards,
Horace
The Clojure compiler must evaluate all top-level forms, because it can be required to run arbitrary code when expanding calls to macros.
The usual solution to issues like the one you describe is to define a top-level Var holding an object of a dereferenceable type, for example an atom or a promise, and have an initialization function provide the value at runtime. (You could also use a delay and specify the value inline; this is less flexible, since it makes it more difficult to use a different value for testing etc.)
I have set up a WebSocket server using http-kit that should accept web socket connections. It is the basic example shown in the http-kit documentation.
The question is:
How do you create a Clojure client that connects to it?
The client can be any Clojure http library, I don't really mind. I already know about Javascript clients, and I believe that Java has an API that I could use from Clojure. But what I am looking for is a Clojure library that supports websockets both for client and server. I saw nothing in http-kit code that would make it easy.
aleph has support for websockets on both server and client. It can take some time to get used to the asynchronous style and aleph's core abstractions, but it's a very good tool once you get the hang of it.
Gniazdo is a WebSocket client for Clojure. It wraps the Jetty's implementation of the protocol.
http-kit's client does not support WebSocket yet(I can't think of a good API for it). Aleph is a good option for this kind of use case. Another option is http.async.client, I've used it in http-kit's server's websocket unit test: here
For those joining us in 2015: being new to this, I just spent a while trying out all the different options available, and it was pretty difficult to find a library that provides an easy way to set up a simple Clojure WebSocket client. (To be fair, it seems like it's not very common for a WebSocket client to be running in a non-browser/JavaScript context, which is why there seems to be so much emphasis on ClojureScript WebSocket clients.)
Although it is not well-documented, http.async.client ended up being the path of least resistance for me. I was able to successfully read streaming data from a WebSocket server and print it to the console by doing this:
(ns example.core
(:require [http.async.client :as async]))
(def url "ws://localhost:1337")
(defn on-open [ws]
(println "Connected to WebSocket."))
(defn on-close [ws code reason]
(println "Connection to WebSocket closed.\n"
(format "(Code %s, reason: %s)" code reason)))
(defn on-error [ws e]
(println "ERROR:" e))
(defn handle-message [ws msg]
(prn "got message:" msg))
(defn -main []
(println "Connecting...")
(-> (async/create-client)
(async/websocket url
:open on-open
:close on-close
:error on-error
:text handle-message
:byte handle-message))
;; Avoid exiting until the process is interrupted.
(while true))
The infinite loop at the end is just to keep the process from ending. Until I press Ctrl-C, messages received from the socket are printed to STDOUT.
According to this announcement, http-kit has support for web sockets. If you're not bound to the asynchronous facilities that http-kit client offer, you could also use clj-http. They have a very similar interface, it seems (I have use but clj-http yet).
(ns playground.experiments.ws
(:use aleph.http lamina.core))
(defn ws-client [] (websocket-client {:url "ws://echo.websocket.org:80"}))
(defn echo [message]
(let [channel (wait-for-result (ws-client) 500)]
(enqueue channel message)
(let [echo (wait-for-result (read-channel channel) 500)]
(close channel)
echo)))
(echo "Echo me!")
I built a basic websocket client and server, it uses java sockets and wraps websocket frames. It's unique in that the server can accept both regular socket connections as well as websockets, simultaneously.
http://github.com/viperscape/gulfstream
Example client code:
(def clienthandler
(with-conn server
(send! server "i'm here!")
(with-data server data (prn "client received" data))
(prn "client is now disconnected")))
(def ws-conn-details {:host "ws://echo.websocket.org/chat",:handler clienthandler})
(def client-conn (start-client ws-conn-details))
I'm trying to stub the RabbitMQ interactions, as those aren't really the main purpose of the application I'm writing.
So, I've tried rebinding the langohr functions in my tests like so:
(defn stub [ch]
(langohr.basic/ack ch 1))
(deftest test-stub
(with-redefs [langohr.basic/ack (fn [a1 a2] true)]
(is (= true (stub "dummy")))))
When I run the test with lein test, I get a
java.lang.ClassCastException:
redwood.env_test$fn__2210$fn__2211 cannot be cast to clojure.lang.IFn$OLO
I've been trying several other ways including different test frameworks to redefine or rebind the langohr lib functions with no progress.
I've tested other scenarios and I've successfully stubbed cheshire (json parsing clojure lib) functions with the above code structure.
I humbly request assistance in understanding why my langohr stubs aren't working and for tips on how I can do this in an elegant manner.
The ClassCastException occurs because langohr.basic/ack is a function that takes a primitive argument - specifically, it is of type clojure.lang.IFn$OLO, where the OLO stands for "object, long, object".
You have to redef it be of the same type. Try this:
(with-redefs [langohr.basic/ack (fn [a1 ^long a2] true)] ...)