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) }