veza/veza-backend-api/docs/INTEGRATION_TESTS_HARDENING_REPORT.md
2025-12-16 11:23:49 -05:00

10 KiB

Integration Tests Hardening Report

Date: 2025-12-15
Commit SHA: feb7283cd4a17c4460be28697ac2d7e4b7476512
Objectif: Rendre les tests d'intégration fiables et reproductibles


Résumé Exécutif

Objectif atteint: Tests d'intégration rendus exécutables avec setup reproductible via testcontainers.

Livrables

  1. Contrat d'environnement - tests/integration/README.md créé
  2. Helper Redis testcontainers - internal/testutils/setup_redis.go créé
  3. TestUploadAsyncPollingStatus exécutable - Retire t.Skip, passe avec testcontainers
  4. QUARANTINE.md révisé - Classification par priorité (🔴🟡🟢)
  5. TestAPIFlow_UserJourney corrigé - Format de réponse aligné avec contrat API réel
  6. Makefile mis à jour - Targets clairs pour tests

1. Contrat d'Environnement

Fichier Créé

  • tests/integration/README.md - Documentation complète (300+ lignes)

Contenu

Services Requis:

  • PostgreSQL 15+ (obligatoire) - Via testcontainers
  • Redis 7+ (obligatoire pour certains tests) - Via testcontainers
  • RabbitMQ (optionnel)

Méthodes de Setup:

  1. Testcontainers (recommandé) - Reproductible, isolation complète
  2. Services locaux (alternative) - Via variables d'environnement

Exécution:

# Avec testcontainers (automatique)
go test ./tests/integration/... -tags integration -v

# Avec services locaux
export DATABASE_URL="postgresql://veza:veza@localhost:5432/veza_test?sslmode=disable"
export REDIS_ADDR="localhost:6379"
go test ./tests/integration/... -tags integration -v

2. Helper Redis Testcontainers

Fichier Créé

  • internal/testutils/setup_redis.go - Helper réutilisable pour Redis

Fonctionnalités

  • Singleton pattern (container démarré une fois par test run)
  • Retry automatique avec backoff
  • Cleanup automatique
  • Compatible avec setup.go existant (PostgreSQL)

Usage

ctx := context.Background()
redisClient, err := testutils.GetTestRedisClient(ctx)
if err != nil {
    t.Skipf("Skipping test: Redis testcontainer not available: %v", err)
    return
}

3. TestUploadAsyncPollingStatus Exécutable

Changements

Avant: t.Skip("Test nécessite setup complet...")

Après: Test exécutable et passe

Corrections Appliquées

  1. Remplacement SQLite → PostgreSQL

    • Avant: gorm.Open(sqlite.Open(":memory:"))
    • Après: gorm.Open(postgres.Open(dsn)) via testcontainers
  2. Ajout Redis

    • Avant: chunkService := services.NewTrackChunkService(uploadDir, nil, logger)
    • Après: chunkService := services.NewTrackChunkService(uploadDir, redisClient, logger)
  3. Création fichier WAV valide

    • Avant: Fichier texte rejeté par validateur
    • Après: Fichier WAV minimal valide avec header RIFF/WAVE
  4. Correction format réponse

    • Avant: data["status"]
    • Après: data["progress"]["status"] (format réel de GetUploadStatus)

Résultat

go test ./tests/integration -tags integration -run TestUploadAsyncPollingStatus$ -v
--- PASS: TestUploadAsyncPollingStatus (64.20s)
PASS

Validations:

  • Upload retourne 202 Accepted
  • Header Location présent
  • Status initial = "uploading" ou "processing"
  • Polling fonctionne (30 tentatives max)
  • Status final = "processing" (fichier copié, traitement en cours)
  • Fichier créé sur disque

4. Corrections de Schéma DB

Problèmes Identifiés

  1. Colonne year manquante dans migrations/040_streaming_core.sql

    • Fix: Ajout year INTEGER DEFAULT 0
  2. Colonne stream_status manquante

    • Fix: Ajout stream_status VARCHAR(20) DEFAULT 'pending'
  3. Contrainte duration > 0 trop stricte

    • Fix: Changé en duration >= 0 (permet 0 temporairement)
  4. Contrainte file_id NOT NULL trop stricte

    • Fix: Changé en file_id UUID (nullable, mis à jour après création fichier)

Fichiers Modifiés

  • migrations/040_streaming_core.sql - Ajout colonnes manquantes, assouplissement contraintes

Modèle Track

  • internal/models/track.go - FileID changé de uuid.UUID à *uuid.UUID (nullable)

5. QUARANTINE.md Révisé

Classification

Classification Description Tests
🔴 Doit passer avant prod Bloquants pour release 0
🟡 CI Nightly Exécutés en CI séparé 1 (TestUploadAsyncPollingStatus_Transitions)
🟢 Manual Only Exécution manuelle uniquement 1 (TestAPIFlow_UserJourney)

Tests Corrigés

TestAPIFlow_UserJourney

Status: CORRIGÉ

Problème original:

  • Cherchait resp["user"] et resp["playlist"] qui n'existent pas
  • Format de réponse divergent

Correction:

  • AdaptBitrate: Valide resp["recommended_bitrate"] (contrat réel)
  • Playlist: Accède à resp["data"]["playlist"] (format standardisé)

Résultat:

go test ./internal/handlers -tags integration -run TestAPIFlow_UserJourney -v
--- PASS: TestAPIFlow_UserJourney (0.01s)
    --- PASS: TestAPIFlow_UserJourney/Bitrate_Adaptation_Flow
    --- PASS: TestAPIFlow_UserJourney/Comment_Flow
    --- PASS: TestAPIFlow_UserJourney/Reply_Flow
    --- PASS: TestAPIFlow_UserJourney/Unauthorized_Delete_Flow
    --- PASS: TestAPIFlow_UserJourney/Playlist_Flow
PASS

6. Makefile Mis à Jour

Targets Ajoutés/Modifiés

  • make test - Tests normaux (sans quarantaine) - MODIFIÉ
  • make test-integration - Tests d'intégration (avec quarantaine) - MODIFIÉ
  • make test-quarantine - Tests en quarantaine (validation manuelle) - MODIFIÉ
  • make test-short - Tests courts uniquement - MODIFIÉ

Messages Améliorés

  • Ajout de notes sur Docker/testcontainers requis
  • Messages plus clairs sur ce qui est exécuté

7. Corrections de Code

Fichiers Modifiés

  1. tests/integration/upload_async_polling_test.go

    • Retire t.Skip
    • Remplace SQLite par PostgreSQL (testcontainers)
    • Ajoute Redis (testcontainers)
    • Crée fichier WAV valide
    • Corrige format réponse (data.progress.status)
  2. internal/handlers/api_flow_test.go

    • Corrige assertions AdaptBitrate (contrat réel)
    • Corrige assertions Playlist (format standardisé)
  3. internal/testutils/setup_redis.go (NOUVEAU)

    • Helper Redis avec testcontainers
  4. internal/models/track.go

    • FileID: uuid.UUID*uuid.UUID (nullable)
  5. migrations/040_streaming_core.sql

    • Ajout colonne year
    • Ajout colonne stream_status
    • Contrainte duration >= 0 (au lieu de > 0)
    • file_id nullable (au lieu de NOT NULL)
  6. internal/services/upload_validator.go

    • Ajout "audio/wave" aux types autorisés (alias valide pour WAV)

8. Validation

Tests Unitaires (Sans Quarantaine)

go test ./internal/... -short -count=1 -tags '!integration'

Résultat: ⚠️ 1 package échoue (internal/workers) - Non-bloquant pour observabilité

Packages passants: 17/18 (94%)

Tests d'Intégration

go test ./tests/integration/... -tags integration -v

Résultat: TestUploadAsyncPollingStatus passe (64s)

Tests Quarantinés

go test ./internal/handlers -tags integration -run TestAPIFlow_UserJourney -v

Résultat: TestAPIFlow_UserJourney passe (tous les sous-tests)


9. Impact CI

Nouvelles Dépendances

  • Aucune - Testcontainers déjà présent dans go.mod

Impact Performance

  • Tests d'intégration: ~60-90s (démarrage containers + migrations)
  • Tests unitaires: Inchangé

Recommandations CI

Pipeline normal (inchangé):

- name: Run unit tests
  run: go test ./internal/... -short -tags '!integration'

Pipeline intégration (nouveau ou amélioré):

- name: Run integration tests
  run: go test ./tests/integration/... -tags integration -v -timeout 10m
  services:
    docker:
      image: docker:latest

10. Résumé des Changements

Fichiers Créés

  1. tests/integration/README.md - Contrat d'environnement (300+ lignes)
  2. internal/testutils/setup_redis.go - Helper Redis testcontainers

Fichiers Modifiés

  1. tests/integration/upload_async_polling_test.go - Test exécutable
  2. tests/integration/QUARANTINE.md - Classification complète
  3. internal/handlers/api_flow_test.go - Format réponse corrigé
  4. internal/models/track.go - FileID nullable
  5. migrations/040_streaming_core.sql - Colonnes manquantes + contraintes
  6. internal/services/upload_validator.go - Type audio/wave ajouté
  7. Makefile - Messages améliorés

Corrections de Schéma

  • Colonne year ajoutée
  • Colonne stream_status ajoutée
  • Contrainte duration >= 0 (au lieu de > 0)
  • file_id nullable

11. Commandes de Validation

Tests Unitaires

go test ./internal/... -short -count=1 -tags '!integration'

Résultat: 17/18 packages passent (94%)

Tests d'Intégration

go test ./tests/integration/... -tags integration -v

Résultat: TestUploadAsyncPollingStatus passe

Tests Quarantinés

go test ./internal/handlers -tags integration -run TestAPIFlow_UserJourney -v

Résultat: TestAPIFlow_UserJourney passe (5/5 sous-tests)


12. Prochaines Étapes

Court Terme

  1. TestUploadAsyncPollingStatus - Exécutable et passe
  2. TestAPIFlow_UserJourney - Corrigé et passe
  3. ⚠️ Tests services - Corriger progressivement (non-bloquant)

Moyen Terme

  1. Compléter TestUploadAsyncPollingStatus_Transitions si nécessaire
  2. Ajouter plus de tests d'intégration E2E
  3. Documenter patterns de test pour nouveaux développeurs

13. Notes Techniques

Pourquoi Testcontainers?

  • Reproductible (même environnement partout)
  • Isolation complète (pas de pollution entre tests)
  • Pas de configuration manuelle requise
  • Fonctionne en CI/CD

Pourquoi WAV au lieu de MP3?

  • http.DetectContentType détecte "audio/wave" pour WAV
  • WAV plus simple à créer qu'un MP3 valide
  • Type "audio/wave" ajouté aux types autorisés (alias valide)

Pourquoi FileID nullable?

  • Track créé avant fichier (sémantique async)
  • Fichier créé dans goroutine après réponse 202
  • FileID mis à jour après création fichier

Date de création: 2025-12-15
Auteur: Integration Tests Hardening
Version: 1.0