- Auth: 30 tests (97 assertions) covering OAuth, sessions, JWT, impersonation, roles - Company: 35 tests (92 assertions) covering profile, 1099, expense reports, permissions - Ledger: 113 tests (148 assertions) covering grid, journal entries, import, reports - Fix existing test failures in running_balance, insights, tx, plaid, graphql - Fix InMemSolrClient to handle Solr query syntax properly - Update behavior docs: auth (42 done), company (32 done), ledger (120 done) - All 478 tests pass with 0 failures, 0 errors
94 lines
4.2 KiB
Clojure
94 lines
4.2 KiB
Clojure
(ns auto-ap.auth.jwt-test
|
|
(:require
|
|
[auto-ap.integration.util :refer [wrap-setup]]
|
|
[auto-ap.routes.auth :as auth]
|
|
[buddy.sign.jwt :as jwt]
|
|
[clj-time.coerce :as coerce]
|
|
[clj-time.core :as time]
|
|
[clojure.test :refer [deftest is testing use-fixtures]]
|
|
[config.core :refer [env]]))
|
|
|
|
(use-fixtures :each wrap-setup)
|
|
|
|
(deftest test-user->jwt-generates-token
|
|
(testing "Behavior 7.1: It should generate a JWT containing the user's role and client access on login"
|
|
(let [user {:db/id 123
|
|
:user/name "Test User"
|
|
:user/role :user-role/user
|
|
:user/clients [{:db/id 1 :client/code "A" :client/locations ["DT"]}
|
|
{:db/id 2 :client/code "B" :client/locations ["MH"]}]}
|
|
token (auth/user->jwt user "fake-oauth-token")]
|
|
(is (= "Test User" (:user token)))
|
|
(is (= "user" (:user/role token)))
|
|
(is (= 123 (:db/id token)))
|
|
(is (= "Test User" (:user/name token)))
|
|
(is (some? (:exp token))))))
|
|
|
|
(deftest test-admin-jwt-compresses-clients
|
|
(testing "Behavior 7.2: It should compress the client list for admin users to fit in the JWT"
|
|
(let [user {:db/id 1
|
|
:user/name "Admin"
|
|
:user/role :user-role/admin
|
|
:user/clients [{:db/id 10 :client/code "A" :client/locations ["DT"]}
|
|
{:db/id 20 :client/code "B" :client/locations ["MH"]}]}
|
|
token (auth/user->jwt user "fake-oauth-token")]
|
|
(is (= "admin" (:user/role token)))
|
|
(is (some? (:gz-clients token)))
|
|
(is (string? (:gz-clients token)))
|
|
(is (nil? (:user/clients token)))
|
|
;; Verify the compressed data can be decompressed
|
|
(let [decompressed (auth/gunzip (:gz-clients token))]
|
|
(is (= [{:db/id 10 :client/code "A" :client/locations ["DT"]}
|
|
{:db/id 20 :client/code "B" :client/locations ["MH"]}]
|
|
decompressed))))))
|
|
|
|
(deftest test-readonly-jwt-compresses-clients
|
|
(testing "Behavior 7.3: It should compress the client list for read-only users to fit in the JWT"
|
|
(let [user {:db/id 2
|
|
:user/name "Read Only"
|
|
:user/role :user-role/read-only
|
|
:user/clients [{:db/id 30 :client/code "C" :client/locations ["DT"]}]}
|
|
token (auth/user->jwt user "fake-oauth-token")]
|
|
(is (= "read-only" (:user/role token)))
|
|
(is (some? (:gz-clients token)))
|
|
(is (string? (:gz-clients token)))
|
|
(is (nil? (:user/clients token)))
|
|
(let [decompressed (auth/gunzip (:gz-clients token))]
|
|
(is (= [{:db/id 30 :client/code "C" :client/locations ["DT"]}]
|
|
decompressed))))))
|
|
|
|
(deftest test-regular-user-jwt-plain-clients
|
|
(testing "Behavior 7.4: It should include a plain client list for regular users in the JWT"
|
|
(let [user {:db/id 3
|
|
:user/name "Regular"
|
|
:user/role :user-role/user
|
|
:user/clients [{:db/id 40 :client/code "D" :client/locations ["DT"]}]}
|
|
token (auth/user->jwt user "fake-oauth-token")]
|
|
(is (= "user" (:user/role token)))
|
|
(is (some? (:user/clients token)))
|
|
(is (sequential? (:user/clients token)))
|
|
(is (nil? (:gz-clients token)))
|
|
(is (= [{:db/id 40 :client/code "D" :client/locations ["DT"]}]
|
|
(:user/clients token))))))
|
|
|
|
(deftest test-api-token
|
|
(testing "Behavior 7.5: It should create API tokens with admin role and 1000-day expiration"
|
|
(let [token-str (auth/make-api-token)
|
|
claims (jwt/unsign token-str (:jwt-secret env) {:alg :hs512})
|
|
exp-dt (coerce/from-long (* 1000 (long (:exp claims))))
|
|
now (time/now)]
|
|
(is (= "API" (:user claims)))
|
|
(is (= "admin" (:user/role claims)))
|
|
(is (= "API" (:user/name claims)))
|
|
(is (some? (:exp claims)))
|
|
;; Verify expiration is approximately 1000 days from now
|
|
(is (time/after? exp-dt now))
|
|
(is (time/before? exp-dt (time/plus now (time/days 1001)))))))
|
|
|
|
(deftest test-gzip-roundtrip
|
|
(testing "gzip and gunzip are inverse operations"
|
|
(let [data [{:db/id 1 :client/code "A"} {:db/id 2 :client/code "B"}]
|
|
compressed (auth/gzip data)
|
|
decompressed (auth/gunzip compressed)]
|
|
(is (= data decompressed)))))
|