(ns auto-ap.auth.session-test (:require [auto-ap.integration.util :refer [admin-token user-token wrap-setup]] [auto-ap.routes.utils :as routes-utils] [auto-ap.session-version :as session-version] [clojure.test :refer [deftest is testing use-fixtures]])) (use-fixtures :each wrap-setup) ;; ============================================================================ ;; Authentication Gate Behaviors (4.1 - 4.3) ;; ============================================================================ (deftest test-wrap-secure (testing "Behavior 4.1: It should allow authenticated requests to proceed to protected routes" (let [handler (routes-utils/wrap-secure (fn [req] {:status 200 :body "OK"})) response (handler {:identity (user-token) :uri "/protected"})] (is (= 200 (:status response))))) (testing "Behavior 4.2: It should redirect unauthenticated users to /login with a redirect-to parameter" (let [handler (routes-utils/wrap-secure (fn [req] {:status 200 :body "OK"})) response (handler {:identity nil :uri "/protected"})] (is (= 302 (:status response))) (is (re-find #"/login\?redirect-to=%2Fprotected" (get-in response [:headers "Location"]))))) (testing "Behavior 4.3: It should return hx-redirect: /login for unauthenticated HTMX requests" (let [handler (routes-utils/wrap-secure (fn [req] {:status 200 :body "OK"})) response (handler {:identity nil :uri "/protected" :headers {"hx-request" "true"}})] (is (= 401 (:status response))) (is (= "/login?redirect-to=%2Fprotected" (get-in response [:headers "hx-redirect"])))))) ;; ============================================================================ ;; Admin Gate Behaviors (5.1 - 5.2) ;; ============================================================================ (deftest test-wrap-admin (testing "Behavior 5.1: It should allow admin requests to proceed to admin-only routes" (with-redefs [com.brunobonacci.mulog.core/log* (fn [& _] nil)] (let [handler (routes-utils/wrap-admin (fn [req] {:status 200 :body "Admin OK"})) response (handler {:identity (admin-token) :uri "/admin"})] (is (= 200 (:status response)))))) (testing "Behavior 5.2: It should redirect non-admin users to /login when accessing admin routes" (with-redefs [com.brunobonacci.mulog.core/log* (fn [& _] nil)] (let [handler (routes-utils/wrap-admin (fn [req] {:status 200 :body "Admin OK"})) response (handler {:identity (user-token) :uri "/admin"})] (is (= 302 (:status response))) (is (re-find #"^/login" (get-in response [:headers "Location"]))))))) ;; ============================================================================ ;; Session Version Behaviors (6.1 - 6.5) ;; ============================================================================ (deftest test-wrap-session-version (let [handler (session-version/wrap-session-version (fn [req] {:status 200 :body "OK"}))] (testing "Behavior 6.1: It should invalidate sessions with outdated version numbers" (let [response (handler {:session {:version 1} :uri "/dashboard" :request-method :get})] (is (not= 200 (:status response))))) (testing "Behavior 6.2: It should redirect to /login when an outdated session accesses normal routes" (let [response (handler {:session {:version 1} :uri "/dashboard" :request-method :get})] (is (= 302 (:status response))) (is (= "/login" (get-in response [:headers "Location"]))))) (testing "Behavior 6.3: It should return hx-redirect: /login for outdated sessions on HTMX routes" (let [response (handler {:session {:version 1} :uri "/dashboard" :request-method :get :headers {"hx-request" "true"}})] (is (= 200 (:status response))) (is (= "/login" (get-in response [:headers "hx-redirect"]))))) (testing "Behavior 6.4: It should return 401 for outdated sessions on GraphQL routes" (let [response (handler {:session {:version 1} :uri "/api/graphql" :request-method :post})] (is (= 401 (:status response))))) (testing "Behavior 6.5: DISCREPANCY - Code treats sessions without version as current, not outdated" ;; The implementation uses (:version session current-session-version) which defaults ;; to the current version when session or version is missing. This means sessions ;; without version are treated as current, NOT outdated as documented. (let [response-no-session (handler {:uri "/dashboard" :request-method :get}) response-empty-session (handler {:session {} :uri "/dashboard" :request-method :get})] (is (= 200 (:status response-no-session)) "Session without version passes through") (is (= 200 (:status response-empty-session)) "Empty session passes through")))))