claude-web-chat/auth_test.go
djuka 3283888738
All checks were successful
Tests / unit-tests (push) Successful in 51s
Inicijalna implementacija Claude Web Chat (Faza 1 - CLI mod)
- 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>
2026-02-18 05:03:40 +00:00

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)
}
}