integrant

Joseph Graham 2024-02-16T04:42:51.643739Z

Has anyone written a guide on how tests runners work with an Integrant project? Trying to find a good pattern to give my tests access to the database connection.

kongeor 2024-02-19T10:01:41.912519Z

I think you are over-complicating things 🙂 Consider your test util looks like this:

(ns gr.cons.river.test-utils
  (:require
    [gr.cons.river.core :as core]
    [integrant.repl.state :as state]
    [next.jdbc :as jdbc]))


(defn system-state 
  []
  (or @core/system state/system))

(defn db []
  (:db.sql/connection (system-state)))

(defn with-empty-db []
  (fn [f]
    (jdbc/execute! (db) ["truncate table nodes restart identity cascade"])
    (jdbc/execute! (db) ["truncate table posts restart identity cascade"])
    (jdbc/execute! (db) ["truncate table releases restart identity cascade"])
    (jdbc/execute! (db) ["truncate table users restart identity cascade"])
    (f)))

(defn system-fixture
  []
  (fn [f]
    (when (nil? (system-state))
      (core/start-app {:opts {:profile :test}}))
    (f)
    (core/stop-app)))
and then in your tests you can just use the db directly:
(ns gr.cons.river.core-test
  (:require
    [gr.cons.river.test-utils :as tu]
    [gr.cons.river.web.models.nodes :as domain]
    [gr.cons.river.web.models.users :as users]
    [clojure.test :refer :all]))

(use-fixtures :once (tu/system-fixture))

(use-fixtures :each (tu/with-empty-db))

(deftest example-test
  (let [;; truncated
        user-1 (users/insert-user (tu/db) "foo")
        user-2 (users/insert-user (tu/db) "bar")
        
        ]
    (domain/insert-posts (tu/db) (:id release-1) files-1)
	;; test setup
	
	
    (testing "first release for first user"
      (is (= [{:depth   1
               :post-id 1
               :visited true}
              {:depth   2
               :post-id 2
               :visited true}
              {:depth   3
               :post-id 3
               :visited false}
              {:depth   4
               :post-id 4
               :visited false}
              {:depth   5
               :post-id 5
               :visited false}] (map #(select-keys % [:post-id :depth :visited]) (domain/find-path-for-user (tu/db) (:id release-1) (:id user-1))))))
	;; truncated
    ))

kongeor 2024-02-19T10:02:31.753069Z

hope that helps

Joseph Graham 2024-02-20T03:37:31.430029Z

Right that's interesting. It looks like you've engineered it so it works in both repl, where you already have the system running, or when run on command-line.

Joseph Graham 2024-02-20T06:21:16.638669Z

That's really helpful kongeor, thanks. With your help I now have a solution that's working well for me!

kongeor 2024-02-20T07:50:54.040849Z

indeed, this works on repl, integration tests, and production builds 🙂 happy to hear it works well ❤️

kongeor 2024-02-16T06:54:57.224619Z

I'm using clj kit for a project which comes with a utility for test fixtures: e.g. https://github.com/kit-clj/kit-examples/blob/master/guestbook/test/clj/kit/guestbook/test_utils.clj

kongeor 2024-02-16T06:55:23.175569Z

then you can just have a function like this:

(defn db []
  (:db.sql/connection (system-state)))

Joseph Graham 2024-02-17T03:23:25.152089Z

alright, thanks. that's good to look at

Joseph Graham 2024-02-17T03:28:06.457709Z

So kit is keeping system in an atom to make it easier to access from other namespaces. Interresting.

Joseph Graham 2024-02-17T03:31:29.006899Z

The alternative option I guess is to make an entirely different integrant system for testing. But then I think I can't use the cognitect test runner because that doesn't have the ability to pass state around the way I need.

Joseph Graham 2024-02-17T04:05:39.344769Z

Even ignoring the cognitect test runner and looking at clojure.test, I see that deftest takes no arguments. So no particular way to pass a database connection to tests. So perhaps an atom is required to share system state with the tests. Unless I ignore deftest and just make functions that call the "is" macro directly. Just trying to figure out if there is a standard pattern to do this sort of stuff with integrant.

WonderLastking 2024-02-16T12:19:38.967439Z

Hi guys, is there any way to have access in a value of a config key? Let's say I have the following config

(defmethod ig/init-key :auth/keycloak
  [_ config]
  (assoc config :access-token (atom {:token        nil
                                     :retry-counter 0})))
I want to use this access-token from other ns. How can I access it ?

weavejester 2024-02-22T18:07:57.770709Z

I'm afraid I don't fully understand the question, unless you're asking about refs (in which case, you can use integrant.core/ref).