142 lines
3.8 KiB
Go
142 lines
3.8 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"veza-backend-api/internal/database"
|
|
"veza-backend-api/internal/models"
|
|
|
|
"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"
|
|
)
|
|
|
|
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"])
|
|
}
|