All checks were successful
Tests / unit-tests (push) Successful in 51s
- Login sa session cookie autentifikacijom - Lista projekata iz filesystem-a - Chat sa Claude CLI preko WebSocket-a - Streaming NDJSON parsiranje iz CLI stdout-a - Sesija zivi nezavisno od browsera (reconnect replay) - Sidebar sa .md fajlovima i markdown renderovanjem - Dark tema, htmx + Go templates - 47 unit testova Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
149 lines
3.5 KiB
Go
149 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSessionManager(t *testing.T) {
|
|
sm := NewSessionManager("test-secret")
|
|
|
|
t.Run("create and get session", func(t *testing.T) {
|
|
sess := sm.Create("admin")
|
|
if sess.Username != "admin" {
|
|
t.Errorf("username = %q, want admin", sess.Username)
|
|
}
|
|
if sess.Token == "" {
|
|
t.Fatal("token is empty")
|
|
}
|
|
|
|
got := sm.Get(sess.Token)
|
|
if got == nil {
|
|
t.Fatal("session not found")
|
|
}
|
|
if got.Username != "admin" {
|
|
t.Errorf("username = %q, want admin", got.Username)
|
|
}
|
|
})
|
|
|
|
t.Run("get nonexistent session", func(t *testing.T) {
|
|
got := sm.Get("nonexistent")
|
|
if got != nil {
|
|
t.Error("expected nil for nonexistent session")
|
|
}
|
|
})
|
|
|
|
t.Run("delete session", func(t *testing.T) {
|
|
sess := sm.Create("user1")
|
|
sm.Delete(sess.Token)
|
|
got := sm.Get(sess.Token)
|
|
if got != nil {
|
|
t.Error("expected nil after delete")
|
|
}
|
|
})
|
|
|
|
t.Run("expired session", func(t *testing.T) {
|
|
sess := sm.Create("user2")
|
|
// Manually set old creation time
|
|
sm.mu.Lock()
|
|
sm.sessions[sess.Token].CreatedAt = time.Now().Add(-25 * time.Hour)
|
|
sm.mu.Unlock()
|
|
|
|
got := sm.Get(sess.Token)
|
|
if got != nil {
|
|
t.Error("expected nil for expired session")
|
|
}
|
|
})
|
|
|
|
t.Run("unique tokens", func(t *testing.T) {
|
|
s1 := sm.Create("a")
|
|
s2 := sm.Create("b")
|
|
if s1.Token == s2.Token {
|
|
t.Error("tokens should be unique")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAuthMiddleware(t *testing.T) {
|
|
sm := NewSessionManager("test-secret")
|
|
sess := sm.Create("admin")
|
|
|
|
protected := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("ok"))
|
|
})
|
|
|
|
handler := AuthMiddleware(sm, protected)
|
|
|
|
t.Run("no cookie redirects to login", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/projects", nil)
|
|
w := httptest.NewRecorder()
|
|
handler.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusSeeOther {
|
|
t.Errorf("status = %d, want %d", w.Code, http.StatusSeeOther)
|
|
}
|
|
loc := w.Header().Get("Location")
|
|
if loc != "/login" {
|
|
t.Errorf("location = %q, want /login", loc)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid cookie redirects to login", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/projects", nil)
|
|
req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: "invalid"})
|
|
w := httptest.NewRecorder()
|
|
handler.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusSeeOther {
|
|
t.Errorf("status = %d, want %d", w.Code, http.StatusSeeOther)
|
|
}
|
|
})
|
|
|
|
t.Run("valid cookie passes through", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/projects", nil)
|
|
req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: sess.Token})
|
|
w := httptest.NewRecorder()
|
|
handler.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("status = %d, want %d", w.Code, http.StatusOK)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSetSessionCookie(t *testing.T) {
|
|
sess := &Session{Token: "test-token", Username: "admin"}
|
|
w := httptest.NewRecorder()
|
|
SetSessionCookie(w, sess)
|
|
|
|
cookies := w.Result().Cookies()
|
|
if len(cookies) != 1 {
|
|
t.Fatalf("expected 1 cookie, got %d", len(cookies))
|
|
}
|
|
if cookies[0].Name != sessionCookieName {
|
|
t.Errorf("cookie name = %q", cookies[0].Name)
|
|
}
|
|
if cookies[0].Value != "test-token" {
|
|
t.Errorf("cookie value = %q", cookies[0].Value)
|
|
}
|
|
if !cookies[0].HttpOnly {
|
|
t.Error("expected HttpOnly")
|
|
}
|
|
}
|
|
|
|
func TestClearSessionCookie(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
ClearSessionCookie(w)
|
|
|
|
cookies := w.Result().Cookies()
|
|
if len(cookies) != 1 {
|
|
t.Fatalf("expected 1 cookie, got %d", len(cookies))
|
|
}
|
|
if cookies[0].MaxAge != -1 {
|
|
t.Errorf("MaxAge = %d, want -1", cookies[0].MaxAge)
|
|
}
|
|
}
|