New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt at spec'ing a namespace #36

merged 5 commits into from Sep 22, 2018
Jump to file or symbol
Failed to load files and symbols.
+117 −34
Diff settings


Just for now

Copy path View file
@@ -0,0 +1,5 @@
(ns caseworker.spec
"Require spec namespaces here to make sure their
corresponding functions are correctly instrumented
by the call in user.clj."
(:require [caseworker.auth.spec :as auth]))
Copy path View file
@@ -3,10 +3,12 @@
[ :as jdbc]
[clojure.repl :refer :all]
[clojure.test :refer [run-tests run-all-tests]]
[clojure.spec.test.alpha :as spec-test]
[caseworker.components.figwheel :as figwheel]
[caseworker.components.sass :as sass]
[caseworker.config :as c]
[caseworker.seed :as seed]
[caseworker.system :as system]
[caseworker.test-helper :as th]
[figwheel-sidecar.repl-api :refer [cljs-repl]]
@@ -19,6 +21,7 @@
(defn make-dev-system
(-> (system/make-system c/env)
(assoc :sass (sass/make-sass-watcher "sass.edn")
:figwheel (figwheel/make-figwheel "figwheel.edn"))))
Copy path View file
@@ -29,7 +29,7 @@
[ring "1.7.0"]
[ring-jetty-component "0.3.1"]
[secretary "1.2.3"]
[selmer "1.12.0"]
[selmer "1.12.1"]
[venantius/accountant "0.2.4"]
[yogthos/config "1.1.1"]
@@ -4,7 +4,6 @@
[camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as csk-extras]
[caseworker.config :as c]
[caseworker.auth :as auth]
[ :as google-auth]
[caseworker.sql :as sql]
[clj-time.core :as t]
@@ -1,7 +1,7 @@
(ns caseworker.api.session.routes
(:require [compojure.api.sweet :as compojure :refer [GET POST PUT DELETE defroutes context]]
[caseworker.api.session.handler :as h]
[caseworker.auth :as auth]
[caseworker.auth.core :as auth]
[caseworker.config :as c]
[caseworker.spec.account :as acc]
[caseworker.spec.organisation :as org]
@@ -1,16 +1,17 @@
(ns caseworker.auth
(ns caseworker.auth.core
(:require [buddy.auth.protocols :as proto]
[buddy.core.hash :as hash]
[buddy.sign.jwt :as jwt]
[buddy.auth.protocols :as proto]
[caseworker.spec.account :as acc]
[caseworker.config :as c]
[caseworker.sql :as sql]
[clj-time.core :as t]
[ring.util.response :as response]))
(def secret (hash/sha256 (:buddy-secret c/env)))
(sql/defsql "caseworker/auth.sql" :as q)
(sql/defsql "caseworker/auth/queries.sql" :as q)
(defn get-session
[request refresh-token]
@@ -1,5 +1,5 @@
-- :name get-account-for-session :? :1
select a.*
select a.account_id,,
from account a join session s on a.account_id = s.account_id
where s.refresh_token = :refresh-token
and s.deleted_at is null;
@@ -0,0 +1,46 @@
(ns caseworker.auth.spec
(:require [buddy.sign.jwt :as jwt]
[caseworker.auth.core :as auth]
[caseworker.spec.account :as acc]
[ :as jdbc]
[clojure.spec.alpha :as s]
[clojure.spec.gen.alpha :as gen]
[clojure.spec.test.alpha :as stest]
[spec-tools.spec :as spec]))
(s/def ::db
(s/def ::exp
(s/and integer? pos?))
(s/def ::access-token
(s/with-gen string?
#(gen/one-of [(gen/string) (gen/fmap auth/refresh-access-token (s/gen ::session))])))
(s/def ::refresh-token
(s/def ::session
(s/keys :req-un [::acc/account-id ::acc/name ::acc/email]))
(s/def :compojure.api.middleware/components
(s/keys :req-un [::db]))
(s/fdef auth/get-session
:args (s/cat :request (s/keys :req [:compojure.api.middleware/components] :req-un [::refresh-token])
:refresh-token ::refresh-token)
:ret ::session)
(s/fdef auth/refresh-access-token
:args (s/cat :session ::session)
:ret (s/and ::access-token
#(contains? (jwt/unsign % auth/secret) :exp))
:fn #(= (get-in % [:args :session])
(-> (:ret %)
(jwt/unsign auth/secret)
(dissoc :exp))))
(s/fdef auth/read-access-token
:args (s/cat :access-token ::access-token)
:ret (s/or :nil nil? :session ::session))
@@ -1,6 +1,6 @@
(ns caseworker.middleware.auth
(:require [buddy.auth.protocols :as proto]
[caseworker.auth :as auth]
[caseworker.auth.core :as auth]
[caseworker.config :as c]
[caseworker.util :as u]
[ring.util.response :as response]
@@ -29,12 +29,13 @@
(-parse [_ req]
(let [access-token (get-in req [:cookies "CW_ACCESS_TOKEN" :value])
refresh-token (get-in req [:cookies "CW_REFRESH_TOKEN" :value])]
{:access-token access-token :refresh-token refresh-token}))
(when (and access-token refresh-token)
{:access-token access-token :refresh-token refresh-token})))
(-authenticate [_ request {:keys [access-token refresh-token]}]
;; if the access token is valid, create a session using its contents
;; the access token is assoc'd into the session to be reused later
(if-let [session (auth/read-access-token access-token)]
(if-let [session (and access-token (auth/read-access-token access-token))]
(assoc session :access-token access-token)
;; if the access token is invalid, but the refresh token *is* valid,
;; use the session retrieved using the refresh token and create
@@ -1,17 +1,20 @@
(ns caseworker.spec.account
(:require #?(:clj [clojure.spec.alpha :as s]
:cljs [cljs.spec.alpha :as s])
[caseworker.spec :as cw]
[spec-tools.spec :as spec]))
#?(:clj [clojure.spec.gen.alpha :as gen]
:cljs [cljs.spec.gen.alpha :as gen])
[caseworker.spec.organisation :as org]
[caseworker.spec.types :as t]))
(s/def ::account-id spec/integer?)
(s/def ::oauth-id spec/string?)
(s/def ::email spec/string?)
(s/def ::name spec/string?)
(s/def ::created-by spec/integer?)
(s/def ::created-at ::cw/date-time)
(s/def ::updated-by spec/integer?)
(s/def ::updated-at ::cw/date-time)
(s/def ::deleted-by (s/nilable spec/integer?))
(s/def ::deleted-at (s/nilable ::cw/date-time))
(s/def ::organisations (s/coll-of (s/keys :req-un [::organisation-id ::name ::slug])))
(s/def ::account-id integer?)
(s/def ::oauth-id string?)
(s/def ::email string?)
(s/def ::name string?)
(s/def ::created-by integer?)
(s/def ::created-at ::t/date-time)
(s/def ::updated-by integer?)
(s/def ::updated-at ::t/date-time)
(s/def ::deleted-by (s/nilable integer?))
(s/def ::deleted-at (s/nilable ::t/date-time))
(s/def ::organisation (s/keys :req-un [::org/organisation-id ::org/name ::org/slug]))
(s/def ::organisations (s/coll-of ::organisation))
@@ -1,6 +1,7 @@
(ns caseworker.spec.organisation
(:require #?(:clj [clojure.spec.alpha :as s]
:cljs [cljs.spec.alpha :as s])
[spec-tools.spec :as spec]))
:cljs [cljs.spec.alpha :as s])))
(s/def ::org-code spec/string?)
(s/def ::organisation-id integer?)
(s/def ::name string?)
(s/def ::slug string?)
@@ -0,0 +1,6 @@
(ns caseworker.spec.types
(:require #?(:clj [clojure.spec.alpha :as s]
:cljs [cljs.spec.alpha :as s]))
#?(:clj (:import [org.joda.time DateTime])))
(s/def ::date-time #?(:clj #(instance? DateTime %) :cljs inst?))
Copy path View file

This file was deleted.

Oops, something went wrong.
@@ -1,6 +1,6 @@
(ns caseworker.api.session.routes-test
(:require [camel-snake-kebab.core :as csk]
[caseworker.auth :as auth]
[caseworker.auth.core :as auth]
[caseworker.db :as db]
[ :as google-auth]
[caseworker.routes :as routes]
@@ -0,0 +1,12 @@
(ns caseworker.auth.core-test
(:require [caseworker.auth.core :as auth]
[caseworker.auth.spec :as auth-spec]
[caseworker.test-helper :as th]
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as st]
[clojure.spec.gen.alpha :as gen]
[clojure.test :as t :refer [deftest testing is are run-tests]]))
(deftest refresh-access-token-test
(th/check `auth/refresh-access-token)
(th/check `auth/read-access-token))
@@ -2,7 +2,7 @@
(:require [cheshire.core :as json]
[ :as io]
[ :as jdbc]
[clojure.spec.alpha :as spec]
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as spec-test]
[clojure.string :as str]
[com.stuartsierra.component :as component]
@@ -14,6 +14,7 @@
[ragtime.jdbc :as rjdbc]
[ragtime.repl :as ragtime]))
;; Replace exception handlers with ones that let the exceptions bubble up
;; for easier understanding of failing tests
@@ -96,3 +97,15 @@
"naadir" {:subject "456" :email "" :name "Naadir"}
"christian" {:subject "789" :email "" :name "Christian"}
(throw (ex-info "Invalid token" {:token token :type :caseworker.errors/invalid}))))
;;; spec.test/check utilities ;;
(alter-var-root #'s/*explain-out* (constantly expound/printer))
(defmacro check
`(let [result# (spec-test/check ~sym)]
(clojure.test/is (nil? (-> result# first :failure))
(expound/explain-results result#))))
ProTip! Use n and p to navigate between commits in a pull request.