veza/veza-backend-api/internal/services/session_service_test.go
2025-12-12 21:34:34 -05:00

141 lines
3.8 KiB
Go

package services
import (
"context"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"veza-backend-api/internal/database"
"veza-backend-api/internal/models"
)
func setupTestSessionService(t *testing.T) (*SessionService, *gorm.DB, *database.Database) {
gormDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
err = gormDB.AutoMigrate(&models.User{})
require.NoError(t, err)
// Create sessions table manually to match what service expects (or if models exist)
// Since models.Session might not be in models package or used by AutoMigrate?
// SessionService setup says:
// query := INSERT INTO sessions (id, user_id, token_hash, created_at, expires_at, ip_address, user_agent)
// The service uses raw SQL, so we need to ensure table exists.
// But SessionService struct 'Session' has db tags.
// Let's generic DB wrapper handling. wrapper uses sql.DB.
// Let's create table manually to be safe or check if Session model is exported in internal/models
// The service defines its OWN Session struct in internal/services/session_service.go
// So we must manually create table in test.
err = gormDB.Exec(`
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
token_hash TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
revoked_at TIMESTAMP,
ip_address TEXT,
user_agent TEXT
)
`).Error
require.NoError(t, err)
sqlDB, err := gormDB.DB()
require.NoError(t, err)
testDB := &database.Database{
DB: sqlDB,
}
logger := zap.NewNop()
service := NewSessionService(testDB, logger)
return service, gormDB, testDB
}
func TestSessionService_CreateAndValidate(t *testing.T) {
service, _, _ := setupTestSessionService(t)
ctx := context.Background()
userID := uuid.New()
token := "test-token"
req := &SessionCreateRequest{
UserID: userID,
Token: token,
IPAddress: "127.0.0.1",
UserAgent: "TestAgent",
ExpiresIn: time.Hour,
}
session, err := service.CreateSession(ctx, req)
assert.NoError(t, err)
assert.NotNil(t, session)
assert.Equal(t, userID, session.UserID)
// Validate
validSession, err := service.ValidateSession(ctx, token)
assert.NoError(t, err)
assert.NotNil(t, validSession)
assert.Equal(t, session.ID, validSession.ID)
}
func TestSessionService_Revoke(t *testing.T) {
service, _, _ := setupTestSessionService(t)
ctx := context.Background()
userID := uuid.New()
token := "test-token-revoke"
req := &SessionCreateRequest{
UserID: userID,
Token: token,
ExpiresIn: time.Hour,
}
_, err := service.CreateSession(ctx, req)
require.NoError(t, err)
err = service.RevokeSession(ctx, token)
assert.NoError(t, err)
// Validate should fail
_, err = service.ValidateSession(ctx, token)
assert.Error(t, err)
}
func TestSessionService_Cleanup(t *testing.T) {
service, _, _ := setupTestSessionService(t)
ctx := context.Background()
userID := uuid.New()
// Create expired session
// Since CreateSession sets expiresAt based on Now(), we'll hack it by short duration and sleeping,
// OR just manually insert an expired one?
// Creating with very short duration is easier if possible, but 1ms might be flaky.
// We can cheat by passing negative duration if logic allows?
// CreateSession: expiresAt := time.Now().Add(expiresIn).
req := &SessionCreateRequest{
UserID: userID,
Token: "expired-token",
ExpiresIn: -1 * time.Hour,
}
// CreateSession checks if expiresIn == 0 defaults to 24h. But negative is fine.
_, err := service.CreateSession(ctx, req)
require.NoError(t, err)
err = service.CleanupExpiredSessions(ctx)
assert.NoError(t, err)
// Check count
stats, err := service.GetSessionStats(ctx)
assert.NoError(t, err)
assert.Equal(t, int64(0), stats["total_active"])
}