Skip to content

Instantly share code, notes, and snippets.

@mdhaney
Created March 18, 2019 20:03
Show Gist options
  • Save mdhaney/c2594605926c97cb1bfe3102c90c0759 to your computer and use it in GitHub Desktop.
Save mdhaney/c2594605926c97cb1bfe3102c90c0759 to your computer and use it in GitHub Desktop.
Datomic Cloud testing
(ns ct-server.test-data
(:require [clojure.test :refer :all]))
(def user1 {:user/username "user1"
:user/email "user1@somedomain.com"
:user/public? false})
(def user2 {:user/username "user2"
:user/email "user2@somedomain.com"
:user/public? false})
(def user3 {:user/username "user3"
:user/email "user3@somedomain.com"
:user/public? false})
(def user4 {:user/username "user4"
:user/email "user4@somedomain.com"
:user/public? false})
(def user5 {:user/username "user5"
:user/email "user5@somedomain.com"
:user/public? false})
(def test-individuals [user1 user2 user3 user4 user5])
(def businessA {:user/username "businessA"
:user/email "businessA@somedomain.com"
:user/public? true})
(def businessB {:user/username "businessB"
:user/email "businessB@somedomain.com"
:user/public? true})
(def businessC {:user/username "businessC"
:user/email "businessC@somedomain.com"
:user/public? true})
(def test-businesses [businessA businessB businessC])
(def test-users (concat test-individuals test-businesses))
(ns test-util
(:require [clojure.test :refer :all]
[fulcro.server :as server]
[datomic.client.api :as d]))
;;
;; config - I'm using Fulcro and their config component, but use whatever you want
;;
(def get-config (memoize (fn [] (server/load-config {:config-path "config/test.edn"}))))
;;
;; client
;;
(def get-client
(memoize
(fn []
(let [{:keys [datomic-cfg]} (get-config)]
(d/client datomic-cfg)))))
;;
;; scratch db
;;
(defmacro with-scratch-db [symbol & body]
`(let [config# (get-config)
client# (get-client)
db-name# (:db-name config#)]
(let [conn# (d/connect client# {:db-name db-name#})
~symbol (d/with-db conn#)]
~@body)))
(defn speculate
"Given a db created using with-db, run a speculative transaction and return the
resultant db"
[db tx-data]
(:db-after (d/with db {:tx-data tx-data})))
(ns users
"Transaction fns and queries for managing user entities"
(:require [datomic.client.api :as d]))
(def nil-entity {:db/id nil})
(defn user-ref
"create a valid reference for a user whether given a db/id or a username"
[r]
(if (string? r) [:user/username r] r))
;;
;; queries
;;
(defn get-user-by-ref
"lookup user by ref (id or lookup-ref), returns nil if user doesn't exist. Takes
an optional pull spec for the third parameter"
([db user-ref]
(get-user-by-ref db user-ref '[*]))
([db user-ref pull-spec]
(try
(let [user (d/pull db pull-spec user-ref)]
(when (and (not-empty user)
(not= user nil-entity))
user))
(catch Exception e nil))))
(defn get-user-by-username
"lookup user by username, returns nil if user doesn't exist. Takes
an optional pull spec for the third parameter"
([db username]
(get-user-by-username db username '[*]))
([db username pull-spec]
(get-user-by-ref db (user-ref username) pull-spec)))
;;
;; transactions
;;
;; NOTE - these are tx-fns deployed as an Ion, but for testing we just call the functions directly
;;
(defn register-user
"create a new user entity with the given minimal attributes"
[db username email public?]
(let [existing-user (get-user-by-username db username)]
(if existing-user
(throw (ex-info "Username already exists" {:existing-user existing-user}))
(if (boolean? public?)
[{:user/username username
:user/email email
:user/public? public?}]
(throw (ex-info "Invalid profile type flag" {:public? public?}))))))
(ns users-test
(:require [clojure.test :refer :all]
[datomic.client.api :as d]
[test-util :refer [speculate with-scratch-db]]
[test-data :as data]
[users :as nut]))
(deftest register-user-tests
(with-scratch-db db
(let [db-with-users (speculate db data/test-users)]
(testing "basic user creation"
(is (= (nut/register-user db "user1" "some@any.com" false)
[{:user/username "user1"
:user/email "some@any.com"
:user/public? false}])))
(testing "creating a user with a duplicate username fails"
(let [user-tx (nut/register-user db "user1" "some@any.com" false)]
(is (thrown? Exception
(nut/register-user
db-with-users "user1" "some@any.com" false)))))
(testing "creating a user with an invalid user type fails"
(is (thrown? Exception
(nut/register-user
db "bad-user" "some@domain.com" "user.type/individual")))
(is (thrown? Exception
(nut/register-user
db "bad-user" "some@domain.com" :user-type/individual)))
(is (thrown? Exception
(nut/register-user
db "bad-user" "some@domain.com" :individual))))
(testing "querying by username"
(is nil? (nut/get-user-by-username db-with-users "missing-user"))
(is (= (nut/get-user-by-username db-with-users "user1" [:user/username])
(select-keys data/user1 [:user/username]))))
(testing "querying by user ref"
(is nil? (nut/get-user-by-ref db-with-users [:user/username "missing-user"]))
(is (= (nut/get-user-by-ref db-with-users [:user/username "user1"] [:user/username])
(select-keys data/user1 [:user/username])))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment