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

326 lines
8.4 KiB
Go

package services
import (
"context"
"os"
"testing"
"time"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// setupTestRedisClient crée un client Redis de test
// Utilise Redis en mémoire ou un Redis de test si disponible
func setupTestRedisClient(t *testing.T) *redis.Client {
redisURL := os.Getenv("REDIS_TEST_URL")
if redisURL == "" {
redisURL = "redis://localhost:6379/15" // Utilise DB 15 pour les tests
}
opts, err := redis.ParseURL(redisURL)
if err != nil {
t.Skipf("Skipping test: failed to parse Redis URL: %v", err)
return nil
}
client := redis.NewClient(opts)
// Test de connexion
ctx := context.Background()
_, err = client.Ping(ctx).Result()
if err != nil {
t.Skipf("Skipping test: Redis not available: %v", err)
return nil
}
// Nettoyer la base de données de test
client.FlushDB(ctx)
// Cleanup: Flush DB après les tests
t.Cleanup(func() {
client.FlushDB(ctx)
client.Close()
})
return client
}
// setupTestTokenBlacklist crée un TokenBlacklist de test
func setupTestTokenBlacklist(t *testing.T) (*TokenBlacklist, *redis.Client) {
client := setupTestRedisClient(t)
if client == nil {
t.Skip("Redis not available")
return nil, nil
}
blacklist := NewTokenBlacklist(client)
return blacklist, client
}
// T0174: Tests pour TokenBlacklist
func TestTokenBlacklist_Add(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_123"
ttl := 1 * time.Hour
err := blacklist.Add(ctx, token, ttl)
assert.NoError(t, err)
// Vérifier que le token est dans la blacklist
isBlacklisted, err := blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.True(t, isBlacklisted)
}
func TestTokenBlacklist_IsBlacklisted_True(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_456"
ttl := 1 * time.Hour
// Ajouter le token
err := blacklist.Add(ctx, token, ttl)
require.NoError(t, err)
// Vérifier qu'il est blacklisté
isBlacklisted, err := blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.True(t, isBlacklisted)
}
func TestTokenBlacklist_IsBlacklisted_False(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_not_blacklisted"
// Vérifier qu'un token non ajouté n'est pas blacklisté
isBlacklisted, err := blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.False(t, isBlacklisted)
}
func TestTokenBlacklist_Expiration(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_expiration"
ttl := 100 * time.Millisecond // TTL très court pour le test
// Ajouter le token avec un TTL court
err := blacklist.Add(ctx, token, ttl)
require.NoError(t, err)
// Vérifier qu'il est blacklisté immédiatement
isBlacklisted, err := blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.True(t, isBlacklisted)
// Attendre que le TTL expire
time.Sleep(150 * time.Millisecond)
// Vérifier qu'il n'est plus blacklisté (expiré automatiquement)
isBlacklisted, err = blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.False(t, isBlacklisted, "Token should be expired and removed from blacklist")
}
func TestTokenBlacklist_Remove(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_remove"
ttl := 1 * time.Hour
// Ajouter le token
err := blacklist.Add(ctx, token, ttl)
require.NoError(t, err)
// Vérifier qu'il est blacklisté
isBlacklisted, err := blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.True(t, isBlacklisted)
// Supprimer le token
err = blacklist.Remove(ctx, token)
assert.NoError(t, err)
// Vérifier qu'il n'est plus blacklisté
isBlacklisted, err = blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.False(t, isBlacklisted)
}
func TestTokenBlacklist_MultipleTokens(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token1 := "test_token_1"
token2 := "test_token_2"
token3 := "test_token_3"
ttl := 1 * time.Hour
// Ajouter plusieurs tokens
err := blacklist.Add(ctx, token1, ttl)
require.NoError(t, err)
err = blacklist.Add(ctx, token2, ttl)
require.NoError(t, err)
// Vérifier que les tokens ajoutés sont blacklistés
isBlacklisted1, err := blacklist.IsBlacklisted(ctx, token1)
assert.NoError(t, err)
assert.True(t, isBlacklisted1)
isBlacklisted2, err := blacklist.IsBlacklisted(ctx, token2)
assert.NoError(t, err)
assert.True(t, isBlacklisted2)
// Vérifier qu'un token non ajouté n'est pas blacklisté
isBlacklisted3, err := blacklist.IsBlacklisted(ctx, token3)
assert.NoError(t, err)
assert.False(t, isBlacklisted3)
}
func TestTokenBlacklist_HashToken(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
token := "test_token_hash"
// Le hash devrait être déterministe
hash1 := blacklist.hashToken(token)
hash2 := blacklist.hashToken(token)
assert.Equal(t, hash1, hash2, "Hash should be deterministic")
assert.NotEqual(t, token, hash1, "Hash should be different from original token")
assert.Len(t, hash1, 64, "SHA256 hash should be 64 characters (hex)")
}
func TestTokenBlacklist_DifferentTokensDifferentHashes(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
token1 := "test_token_1"
token2 := "test_token_2"
hash1 := blacklist.hashToken(token1)
hash2 := blacklist.hashToken(token2)
assert.NotEqual(t, hash1, hash2, "Different tokens should have different hashes")
}
func TestTokenBlacklist_AddWithDifferentTTL(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token1 := "test_token_ttl_1"
token2 := "test_token_ttl_2"
token3 := "test_token_ttl_3"
// Ajouter des tokens avec différents TTL
err := blacklist.Add(ctx, token1, 1*time.Second)
require.NoError(t, err)
err = blacklist.Add(ctx, token2, 2*time.Second)
require.NoError(t, err)
err = blacklist.Add(ctx, token3, 500*time.Millisecond)
require.NoError(t, err)
// Tous devraient être blacklistés immédiatement
isBlacklisted1, _ := blacklist.IsBlacklisted(ctx, token1)
assert.True(t, isBlacklisted1)
isBlacklisted2, _ := blacklist.IsBlacklisted(ctx, token2)
assert.True(t, isBlacklisted2)
isBlacklisted3, _ := blacklist.IsBlacklisted(ctx, token3)
assert.True(t, isBlacklisted3)
// Attendre que le premier expire
time.Sleep(600 * time.Millisecond)
isBlacklisted3, _ = blacklist.IsBlacklisted(ctx, token3)
assert.False(t, isBlacklisted3, "Token3 should be expired")
// Les autres devraient encore être là
isBlacklisted1, _ = blacklist.IsBlacklisted(ctx, token1)
assert.True(t, isBlacklisted1)
isBlacklisted2, _ = blacklist.IsBlacklisted(ctx, token2)
assert.True(t, isBlacklisted2)
// Attendre que token1 expire
time.Sleep(500 * time.Millisecond)
isBlacklisted1, _ = blacklist.IsBlacklisted(ctx, token1)
assert.False(t, isBlacklisted1, "Token1 should be expired")
// Token2 devrait encore être là
isBlacklisted2, _ = blacklist.IsBlacklisted(ctx, token2)
assert.True(t, isBlacklisted2)
// Attendre que token2 expire
time.Sleep(1 * time.Second)
isBlacklisted2, _ = blacklist.IsBlacklisted(ctx, token2)
assert.False(t, isBlacklisted2, "Token2 should be expired")
}
func TestTokenBlacklist_AddTwice(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_add_twice"
ttl := 1 * time.Hour
// Ajouter le token deux fois
err := blacklist.Add(ctx, token, ttl)
require.NoError(t, err)
err = blacklist.Add(ctx, token, ttl)
require.NoError(t, err) // Ne devrait pas retourner d'erreur
// Vérifier qu'il est toujours blacklisté
isBlacklisted, err := blacklist.IsBlacklisted(ctx, token)
assert.NoError(t, err)
assert.True(t, isBlacklisted)
}
func TestTokenBlacklist_RemoveNonExistent(t *testing.T) {
blacklist, _ := setupTestTokenBlacklist(t)
if blacklist == nil {
return
}
ctx := context.Background()
token := "test_token_not_exists"
// Supprimer un token qui n'existe pas ne devrait pas retourner d'erreur
err := blacklist.Remove(ctx, token)
assert.NoError(t, err)
}