package database import ( "os" "testing" "veza-backend-api/internal/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/sqlite" "gorm.io/gorm" ) // setupTestDB crée une base de données de test en mémoire func setupTestDB(t *testing.T) *gorm.DB { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err, "Failed to open test database") return db } // TestRunMigrations teste l'exécution des migrations GORM func TestRunMigrations(t *testing.T) { db := setupTestDB(t) err := RunMigrations(db) assert.NoError(t, err, "RunMigrations should not return an error") // Vérifier que les tables existent assert.True(t, db.Migrator().HasTable(&models.User{}), "Users table should exist") assert.True(t, db.Migrator().HasTable(&models.RefreshToken{}), "RefreshTokens table should exist") assert.True(t, db.Migrator().HasTable(&models.Track{}), "Tracks table should exist") assert.True(t, db.Migrator().HasTable(&models.Playlist{}), "Playlists table should exist") assert.True(t, db.Migrator().HasTable(&models.PlaylistTrack{}), "PlaylistTracks table should exist") assert.True(t, db.Migrator().HasTable(&models.Message{}), "Messages table should exist") assert.True(t, db.Migrator().HasTable(&models.Room{}), "Rooms table should exist") assert.True(t, db.Migrator().HasTable(&models.RoomMember{}), "RoomMembers table should exist") } // TestRunMigrations_Idempotent teste que les migrations sont idempotentes func TestRunMigrations_Idempotent(t *testing.T) { db := setupTestDB(t) // Exécuter les migrations deux fois err := RunMigrations(db) assert.NoError(t, err, "First RunMigrations should not return an error") err = RunMigrations(db) assert.NoError(t, err, "Second RunMigrations should not return an error") // Vérifier que les tables existent toujours assert.True(t, db.Migrator().HasTable(&models.User{})) assert.True(t, db.Migrator().HasTable(&models.Track{})) } // TestAddIndexes teste la création des indexes func TestAddIndexes(t *testing.T) { db := setupTestDB(t) // Exécuter les migrations (qui incluent addIndexes) err := RunMigrations(db) require.NoError(t, err, "RunMigrations should succeed") // Pour SQLite, vérifier que les indexes existent en vérifiant les migrations // Note: SQLite stocke les indexes différemment de PostgreSQL // On vérifie plutôt que les migrations n'ont pas d'erreur // et que les tables peuvent être créées avec les indexes // Vérifier que les tables ont bien les colonnes indexées var user models.User // Vérifier que l'index existe (HasIndex retourne un bool, pas une erreur) hasIndex := db.Migrator().HasIndex(&user, "idx_users_email") // SQLite peut avoir un comportement différent, donc on accepte les deux cas // L'important est que la migration fonctionne sans erreur _ = hasIndex // Vérifier qu'on peut créer un utilisateur (ce qui teste les contraintes) user = models.User{ Username: "testuser", Email: "test@example.com", Role: "user", } err = db.Create(&user).Error assert.NoError(t, err, "Should be able to create a user") // Vérifier qu'on ne peut pas créer un utilisateur avec un email dupliqué user2 := models.User{ Username: "testuser2", Email: "test@example.com", Role: "user", } err = db.Create(&user2).Error assert.Error(t, err, "Should not be able to create user with duplicate email") } // TestMigrations_UserRelations teste les relations entre User et autres modèles func TestMigrations_UserRelations(t *testing.T) { db := setupTestDB(t) err := RunMigrations(db) require.NoError(t, err) // Créer un utilisateur user := models.User{ Username: "testuser", Email: "test@example.com", Role: "user", } err = db.Create(&user).Error require.NoError(t, err) // Créer un refresh token pour cet utilisateur refreshToken := models.RefreshToken{ UserID: user.ID, TokenHash: "hash123", ExpiresAt: db.NowFunc().AddDate(0, 0, 7), } err = db.Create(&refreshToken).Error assert.NoError(t, err, "Should be able to create refresh token") // Vérifier que la relation fonctionne var retrievedToken models.RefreshToken err = db.First(&retrievedToken, refreshToken.ID).Error assert.NoError(t, err) assert.Equal(t, user.ID, retrievedToken.UserID) } // TestMigrations_TrackRelations teste les relations entre Track et User func TestMigrations_TrackRelations(t *testing.T) { db := setupTestDB(t) err := RunMigrations(db) require.NoError(t, err) // Créer un utilisateur user := models.User{ Username: "creator", Email: "creator@example.com", Role: "user", } err = db.Create(&user).Error require.NoError(t, err) // Créer une track pour cet utilisateur track := models.Track{ UserID: user.ID, Title: "Test Track", Duration: 180, } err = db.Create(&track).Error assert.NoError(t, err, "Should be able to create track") // Vérifier que la relation fonctionne var retrievedTrack models.Track err = db.First(&retrievedTrack, track.ID).Error assert.NoError(t, err) assert.Equal(t, user.ID, retrievedTrack.UserID) } // TestMigrations_PlaylistRelations teste les relations pour les playlists func TestMigrations_PlaylistRelations(t *testing.T) { db := setupTestDB(t) err := RunMigrations(db) require.NoError(t, err) // Créer un utilisateur user := models.User{ Username: "playlist_owner", Email: "owner@example.com", Role: "user", } err = db.Create(&user).Error require.NoError(t, err) // Créer une playlist playlist := models.Playlist{ UserID: user.ID, Title: "My Playlist", } err = db.Create(&playlist).Error require.NoError(t, err) // Créer une track track := models.Track{ UserID: user.ID, Title: "Track 1", Duration: 200, } err = db.Create(&track).Error require.NoError(t, err) // Ajouter la track à la playlist playlistTrack := models.PlaylistTrack{ PlaylistID: playlist.ID, TrackID: track.ID, Position: 1, } err = db.Create(&playlistTrack).Error assert.NoError(t, err, "Should be able to add track to playlist") // Vérifier la relation var retrievedPlaylist models.Playlist err = db.Preload("Tracks").First(&retrievedPlaylist, playlist.ID).Error assert.NoError(t, err) assert.Len(t, retrievedPlaylist.Tracks, 1) } // TestMigrations_RoomRelations teste les relations pour les rooms et messages func TestMigrations_RoomRelations(t *testing.T) { db := setupTestDB(t) err := RunMigrations(db) require.NoError(t, err) // Créer un utilisateur user := models.User{ Username: "room_creator", Email: "creator@example.com", Role: "user", } err = db.Create(&user).Error require.NoError(t, err) // Créer une room room := models.Room{ Name: "Test Room", Type: "public", CreatedBy: user.ID, } err = db.Create(&room).Error require.NoError(t, err) // Ajouter l'utilisateur à la room roomMember := models.RoomMember{ RoomID: room.ID, UserID: user.ID, Role: "owner", } err = db.Create(&roomMember).Error assert.NoError(t, err, "Should be able to add user to room") // Créer un message dans la room message := models.Message{ RoomID: room.ID, UserID: user.ID, Content: "Hello, world!", Type: "text", } err = db.Create(&message).Error assert.NoError(t, err, "Should be able to create message") // Vérifier les relations var retrievedRoom models.Room err = db.Preload("Members").Preload("Messages").First(&retrievedRoom, room.ID).Error assert.NoError(t, err) assert.Len(t, retrievedRoom.Members, 1) assert.Len(t, retrievedRoom.Messages, 1) } // TestEmailVerificationTokensMigration teste que la migration pour la table email_verification_tokens existe et peut être lue func TestEmailVerificationTokensMigration(t *testing.T) { migrationPath := "migrations/018_create_email_verification_tokens.sql" // Vérifier que le fichier existe content, err := os.ReadFile(migrationPath) require.NoError(t, err, "Migration file should exist and be readable") // Vérifier que le contenu n'est pas vide assert.NotEmpty(t, content, "Migration file should not be empty") // Vérifier que le contenu contient les éléments essentiels contentStr := string(content) assert.Contains(t, contentStr, "CREATE TABLE email_verification_tokens", "Should create email_verification_tokens table") assert.Contains(t, contentStr, "user_id BIGINT", "Should have user_id column") assert.Contains(t, contentStr, "token VARCHAR(255)", "Should have token column") assert.Contains(t, contentStr, "expires_at TIMESTAMP", "Should have expires_at column") assert.Contains(t, contentStr, "used BOOLEAN", "Should have used column") assert.Contains(t, contentStr, "REFERENCES users(id) ON DELETE CASCADE", "Should have foreign key constraint") assert.Contains(t, contentStr, "idx_email_verification_tokens_token", "Should have index on token") assert.Contains(t, contentStr, "idx_email_verification_tokens_user_id", "Should have index on user_id") assert.Contains(t, contentStr, "idx_email_verification_tokens_expires_at", "Should have index on expires_at") }