veza/veza-backend-api/internal/services/refresh_token_service_test.go

287 lines
7.4 KiB
Go
Raw Normal View History

2025-12-03 19:29:37 +00:00
package services
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"veza-backend-api/internal/models"
)
// setupTestRefreshTokenService crée un RefreshTokenService de test avec une base de données en mémoire
func setupTestRefreshTokenService(t *testing.T) (*RefreshTokenService, *gorm.DB) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("Failed to open test database: %v", err)
}
// Auto-migrate
err = db.AutoMigrate(&models.User{}, &models.RefreshToken{})
if err != nil {
t.Fatalf("Failed to migrate: %v", err)
}
// Create a test user
user := &models.User{
Email: "test@example.com",
Username: "testuser",
Role: "user",
IsActive: true,
}
db.Create(user)
service := NewRefreshTokenService(db)
return service, db
}
func TestRefreshTokenService_Store(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
token := "test-refresh-token-123"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token, ttl)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
// Verify token was stored (check by hash)
var storedToken models.RefreshToken
tokenHash := service.hashToken(token)
err = db.Where("user_id = ? AND token_hash = ?", user.ID, tokenHash).First(&storedToken).Error
assert.NoError(t, err)
assert.Equal(t, user.ID, storedToken.UserID)
assert.Equal(t, tokenHash, storedToken.TokenHash)
}
func TestRefreshTokenService_Validate_ValidToken(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
token := "valid-refresh-token"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Validate the token
err = service.Validate(user.ID, token)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
}
func TestRefreshTokenService_Validate_InvalidToken(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
// Try to validate a token that doesn't exist
err := service.Validate(user.ID, "non-existent-token")
assert.Error(t, err)
assert.Equal(t, "refresh token not found", err.Error())
2025-12-03 19:29:37 +00:00
}
func TestRefreshTokenService_Validate_ExpiredToken(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
token := "expired-refresh-token"
ttl := -1 * time.Hour // Expired 1 hour ago
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Validate the expired token
err = service.Validate(user.ID, token)
assert.Error(t, err)
assert.Equal(t, "refresh token expired", err.Error())
2025-12-03 19:29:37 +00:00
}
func TestRefreshTokenService_Validate_WrongUser(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
// Create another user
otherUser := &models.User{
Email: "other@example.com",
Username: "otheruser",
Role: "user",
IsActive: true,
}
db.Create(otherUser)
token := "user-specific-token"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
// Store token for first user
err := service.Store(user.ID, token, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Try to validate with wrong user ID
err = service.Validate(otherUser.ID, token)
assert.Error(t, err)
assert.Equal(t, "refresh token not found", err.Error())
2025-12-03 19:29:37 +00:00
}
func TestRefreshTokenService_Revoke(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
token := "token-to-revoke"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Verify token exists
err = service.Validate(user.ID, token)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Revoke the token
err = service.Revoke(user.ID, token)
assert.NoError(t, err)
// Verify token is no longer valid
err = service.Validate(user.ID, token)
assert.Error(t, err)
assert.Equal(t, "refresh token not found", err.Error())
2025-12-03 19:29:37 +00:00
}
func TestRefreshTokenService_Revoke_NonExistentToken(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
// Try to revoke a token that doesn't exist
err := service.Revoke(user.ID, "non-existent-token")
assert.NoError(t, err)
// assert.Contains(t, err.Error(), "not found") // Service returns nil (idempotent)
2025-12-03 19:29:37 +00:00
}
func TestRefreshTokenService_RevokeAll(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
// Store multiple tokens
token1 := "token-1"
token2 := "token-2"
token3 := "token-3"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token1, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
err = service.Store(user.ID, token2, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
err = service.Store(user.ID, token3, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Verify all tokens are valid
err = service.Validate(user.ID, token1)
assert.NoError(t, err)
err = service.Validate(user.ID, token2)
assert.NoError(t, err)
err = service.Validate(user.ID, token3)
assert.NoError(t, err)
2025-12-03 19:29:37 +00:00
// Revoke all tokens
err = service.RevokeAll(user.ID)
assert.NoError(t, err)
// Verify all tokens are revoked
err = service.Validate(user.ID, token1)
assert.Error(t, err)
err = service.Validate(user.ID, token2)
assert.Error(t, err)
err = service.Validate(user.ID, token3)
assert.Error(t, err)
2025-12-03 19:29:37 +00:00
}
func TestRefreshTokenService_hashToken(t *testing.T) {
service, _ := setupTestRefreshTokenService(t)
token := "test-token"
hash1 := service.hashToken(token)
hash2 := service.hashToken(token)
// Same token should produce same hash
assert.Equal(t, hash1, hash2)
assert.Len(t, hash1, 64) // SHA-256 produces 64 hex characters
// Different tokens should produce different hashes
hash3 := service.hashToken("different-token")
assert.NotEqual(t, hash1, hash3)
}
func TestRefreshTokenService_StoreMultipleTokens(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
// Store multiple tokens for the same user
token1 := "token-1"
token2 := "token-2"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token1, ttl)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
err = service.Store(user.ID, token2, ttl)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
// Both tokens should be valid
err = service.Validate(user.ID, token1)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
err = service.Validate(user.ID, token2)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
// Verify both tokens are stored in database
var count int64
db.Model(&models.RefreshToken{}).Where("user_id = ?", user.ID).Count(&count)
assert.Equal(t, int64(2), count)
}
func TestRefreshTokenService_Validate_AfterRevokeOne(t *testing.T) {
service, db := setupTestRefreshTokenService(t)
var user models.User
db.Where("email = ?", "test@example.com").First(&user)
token1 := "token-1"
token2 := "token-2"
ttl := 30 * 24 * time.Hour
2025-12-03 19:29:37 +00:00
err := service.Store(user.ID, token1, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
err = service.Store(user.ID, token2, ttl)
2025-12-03 19:29:37 +00:00
require.NoError(t, err)
// Revoke only token1
err = service.Revoke(user.ID, token1)
assert.NoError(t, err)
// token1 should be invalid
err = service.Validate(user.ID, token1)
assert.Error(t, err)
2025-12-03 19:29:37 +00:00
// token2 should still be valid
err = service.Validate(user.ID, token2)
2025-12-03 19:29:37 +00:00
assert.NoError(t, err)
}