Files
gochat/backend/tests/e2e/session_e2e_test.go
T
2026-08-18 00:55:45 +08:00

278 lines
7.6 KiB
Go

package e2e
import (
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/gochat/gochat/internal/auth"
"github.com/gochat/gochat/internal/config"
"github.com/gochat/gochat/internal/middleware"
)
// SessionE2ETestSuite tests session store and middleware integration.
type SessionE2ETestSuite struct {
suite.Suite
store *auth.SessionStore
sessionCfg config.SessionConfig
}
func TestSessionE2ETestSuite(t *testing.T) {
suite.Run(t, new(SessionE2ETestSuite))
}
func (s *SessionE2ETestSuite) SetupTest() {
s.sessionCfg = config.SessionConfig{
Enabled: true,
ExpirySeconds: 3600,
TokenLength: 32,
HeaderName: "X-Session-ID",
CleanupInterval: 300,
}
s.store = auth.NewSessionStore(&s.sessionCfg)
}
// --- Session Store Tests ---
func (s *SessionE2ETestSuite) TestSessionCreate() {
session, err := s.store.Create(1, 100, "agent", "email")
assert.NoError(s.T(), err)
assert.NotEmpty(s.T(), session.ID)
assert.Equal(s.T(), uint(1), session.UserID)
assert.Equal(s.T(), uint(100), session.AccountID)
assert.Equal(s.T(), "agent", session.Role)
assert.Equal(s.T(), "email", session.Provider)
assert.False(s.T(), session.CreatedAt.IsZero())
assert.False(s.T(), session.ExpiresAt.IsZero())
}
func (s *SessionE2ETestSuite) TestSessionGet() {
session, err := s.store.Create(2, 200, "administrator", "google")
assert.NoError(s.T(), err)
retrieved, err := s.store.Get(session.ID)
assert.NoError(s.T(), err)
assert.Equal(s.T(), session.ID, retrieved.ID)
assert.Equal(s.T(), uint(2), retrieved.UserID)
}
func (s *SessionE2ETestSuite) TestSessionGetNotFound() {
_, err := s.store.Get("nonexistent-session-id")
assert.Error(s.T(), err)
}
func (s *SessionE2ETestSuite) TestSessionDelete() {
session, err := s.store.Create(3, 300, "agent", "oidc")
assert.NoError(s.T(), err)
err = s.store.Delete(session.ID)
assert.NoError(s.T(), err)
_, err = s.store.Get(session.ID)
assert.Error(s.T(), err)
}
func (s *SessionE2ETestSuite) TestSessionDeleteByUserID() {
s.store.Create(4, 400, "agent", "email")
s.store.Create(4, 500, "agent", "email") // same user, different account
s.store.Create(5, 600, "administrator", "email") // different user
count := s.store.DeleteByUserID(4)
assert.Equal(s.T(), 2, count)
// User 5's session should still exist
assert.Equal(s.T(), 1, s.store.Count())
}
func (s *SessionE2ETestSuite) TestSessionRefresh() {
session, err := s.store.Create(6, 700, "agent", "email")
assert.NoError(s.T(), err)
originalExpiry := session.ExpiresAt
refreshed, err := s.store.Refresh(session.ID)
assert.NoError(s.T(), err)
assert.True(s.T(), refreshed.ExpiresAt.After(originalExpiry))
}
func (s *SessionE2ETestSuite) TestSessionSetGetData() {
session, err := s.store.Create(7, 800, "agent", "email")
assert.NoError(s.T(), err)
err = s.store.SetData(session.ID, "theme", "dark")
assert.NoError(s.T(), err)
val, err := s.store.GetData(session.ID, "theme")
assert.NoError(s.T(), err)
assert.Equal(s.T(), "dark", val)
}
func (s *SessionE2ETestSuite) TestSessionCleanupExpired() {
// Create a session with short expiry
shortCfg := config.SessionConfig{
Enabled: true,
ExpirySeconds: 1, // 1 second
TokenLength: 32,
}
shortStore := auth.NewSessionStore(&shortCfg)
session, err := shortStore.Create(8, 900, "agent", "email")
assert.NoError(s.T(), err)
// Wait for expiry
time.Sleep(2 * time.Second)
count := shortStore.CleanupExpired()
assert.Equal(s.T(), 1, count)
_, err = shortStore.Get(session.ID)
assert.Error(s.T(), err)
}
func (s *SessionE2ETestSuite) TestSessionCount() {
initialCount := s.store.Count()
s.store.Create(9, 1000, "agent", "email")
assert.Equal(s.T(), initialCount+1, s.store.Count())
}
// --- Session Middleware Tests ---
func (s *SessionE2ETestSuite) TestSessionMiddlewareWithHeader() {
session, err := s.store.Create(10, 1100, "agent", "email")
assert.NoError(s.T(), err)
mwCfg := middleware.DefaultSessionMiddlewareConfig()
router := gin.New()
router.Use(middleware.SessionMiddleware(s.store, mwCfg))
router.GET("/test", func(c *gin.Context) {
sessionID, _ := c.Get("session_id")
c.JSON(200, gin.H{"session_id": sessionID})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/test", nil)
req.Header.Set("X-Session-ID", session.ID)
router.ServeHTTP(w, req)
assert.Equal(s.T(), 200, w.Code)
}
func (s *SessionE2ETestSuite) TestSessionMiddlewareWithCookie() {
session, err := s.store.Create(11, 1200, "agent", "email")
assert.NoError(s.T(), err)
mwCfg := middleware.DefaultSessionMiddlewareConfig()
router := gin.New()
router.Use(middleware.SessionMiddleware(s.store, mwCfg))
router.GET("/test", func(c *gin.Context) {
sessionID, exists := c.Get("session_id")
if exists {
c.JSON(200, gin.H{"session_id": sessionID})
} else {
c.JSON(200, gin.H{"session_id": nil})
}
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/test", nil)
req.AddCookie(&http.Cookie{Name: "_gochat_session", Value: session.ID})
router.ServeHTTP(w, req)
assert.Equal(s.T(), 200, w.Code)
}
func (s *SessionE2ETestSuite) TestSessionMiddlewareNoSession() {
mwCfg := middleware.DefaultSessionMiddlewareConfig()
router := gin.New()
router.Use(middleware.SessionMiddleware(s.store, mwCfg))
router.GET("/test", func(c *gin.Context) {
_, exists := c.Get("session_id")
c.JSON(200, gin.H{"has_session": exists})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/test", nil)
router.ServeHTTP(w, req)
assert.Equal(s.T(), 200, w.Code)
}
func (s *SessionE2ETestSuite) TestSessionMiddlewareSkipPath() {
mwCfg := middleware.DefaultSessionMiddlewareConfig()
router := gin.New()
router.Use(middleware.SessionMiddleware(s.store, mwCfg))
router.GET("/api/v1/auth/login", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/auth/login", nil)
router.ServeHTTP(w, req)
assert.Equal(s.T(), 200, w.Code)
}
func (s *SessionE2ETestSuite) TestSessionMiddlewareExpiredSession() {
shortCfg := config.SessionConfig{
Enabled: true,
ExpirySeconds: 1,
TokenLength: 32,
}
shortStore := auth.NewSessionStore(&shortCfg)
session, err := shortStore.Create(12, 1300, "agent", "email")
assert.NoError(s.T(), err)
// Wait for expiry
time.Sleep(2 * time.Second)
mwCfg := middleware.DefaultSessionMiddlewareConfig()
router := gin.New()
router.Use(middleware.SessionMiddleware(shortStore, mwCfg))
router.GET("/test", func(c *gin.Context) {
_, exists := c.Get("session_id")
c.JSON(200, gin.H{"has_session": exists})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/test", nil)
req.Header.Set("X-Session-ID", session.ID)
router.ServeHTTP(w, req)
assert.Equal(s.T(), 200, w.Code) // doesn't abort, just no session
}
func (s *SessionE2ETestSuite) TestRequireSessionMiddleware() {
router := gin.New()
router.Use(middleware.RequireSession())
router.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// Without session_id in context → 401
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/test", nil)
router.ServeHTTP(w, req)
assert.Equal(s.T(), 401, w.Code)
// With session_id in context → 200
router2 := gin.New()
router2.Use(func(c *gin.Context) {
c.Set("session_id", "test-session-123")
c.Next()
})
router2.Use(middleware.RequireSession())
router2.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
w2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/test", nil)
router2.ServeHTTP(w2, req2)
assert.Equal(s.T(), 200, w2.Code)
}