278 lines
7.6 KiB
Go
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)
|
|
}
|