veza/veza-backend-api/internal/database/migrations_test.go
2025-12-03 20:29:37 +01:00

283 lines
8.9 KiB
Go

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