355 lines
12 KiB
Go
355 lines
12 KiB
Go
package transactions
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap/zaptest"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
"veza-backend-api/internal/models"
|
|
"veza-backend-api/internal/repositories"
|
|
"veza-backend-api/internal/services"
|
|
"veza-backend-api/internal/testutils"
|
|
)
|
|
|
|
// setupTestDB crée une DB de test avec testcontainers
|
|
func setupTestDBForPlaylist(t *testing.T) *gorm.DB {
|
|
ctx := context.Background()
|
|
dsn, err := testutils.GetTestContainerDB(ctx)
|
|
require.NoError(t, err, "Failed to setup test database")
|
|
|
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|
require.NoError(t, err, "Failed to open database connection")
|
|
|
|
// Auto-migrate models nécessaires
|
|
err = db.AutoMigrate(
|
|
&models.User{},
|
|
&models.Track{},
|
|
&models.Playlist{},
|
|
&models.PlaylistTrack{},
|
|
&models.PlaylistCollaborator{},
|
|
)
|
|
require.NoError(t, err, "Failed to migrate database")
|
|
|
|
return db
|
|
}
|
|
|
|
// cleanupTestDB nettoie la DB entre les tests
|
|
func cleanupTestDBForPlaylist(t *testing.T, db *gorm.DB) {
|
|
db.Exec("TRUNCATE TABLE playlist_tracks CASCADE")
|
|
db.Exec("TRUNCATE TABLE playlist_collaborators CASCADE")
|
|
db.Exec("TRUNCATE TABLE playlists CASCADE")
|
|
db.Exec("TRUNCATE TABLE tracks CASCADE")
|
|
db.Exec("TRUNCATE TABLE users CASCADE")
|
|
}
|
|
|
|
// createTestUser crée un utilisateur de test
|
|
func createTestUserForPlaylist(t *testing.T, db *gorm.DB) *models.User {
|
|
user := &models.User{
|
|
Username: "testuser_" + uuid.New().String()[:8],
|
|
Slug: "testuser_" + uuid.New().String()[:8], // Unique slug
|
|
Email: "test_" + uuid.New().String()[:8] + "@example.com",
|
|
PasswordHash: "$2a$10$examplehash",
|
|
IsActive: true,
|
|
IsVerified: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
return user
|
|
}
|
|
|
|
// createTestTrack crée un track de test
|
|
func createTestTrack(t *testing.T, db *gorm.DB, userID uuid.UUID) uuid.UUID {
|
|
// Create a dummy file first (required by FK)
|
|
fileID := uuid.New()
|
|
err := db.Exec(`
|
|
INSERT INTO files (id, user_id, filename, original_filename, mime_type, file_size, storage_path, url, is_public)
|
|
VALUES (?, ?, 'test_track.mp3', 'test_track.mp3', 'audio/mpeg', 5242880, '/test/track.mp3', 'http://example.com/test.mp3', true)
|
|
`, fileID, userID).Error
|
|
require.NoError(t, err, "Failed to create dummy file for track")
|
|
|
|
trackID := uuid.New()
|
|
track := &models.Track{
|
|
ID: trackID,
|
|
UserID: userID, // Maps to creator_id now
|
|
FileID: fileID,
|
|
Title: "Test Track " + uuid.New().String()[:8],
|
|
Artist: "Test Artist",
|
|
Duration: 180,
|
|
FilePath: "/test/track.mp3",
|
|
FileSize: 5242880,
|
|
Format: "mp3",
|
|
IsPublic: true,
|
|
Status: "completed",
|
|
}
|
|
err = db.Create(track).Error
|
|
require.NoError(t, err)
|
|
return track.ID
|
|
}
|
|
|
|
// createTestPlaylistWithTracks crée une playlist avec des tracks
|
|
func createTestPlaylistWithTracks(t *testing.T, db *gorm.DB, userID uuid.UUID, trackCount int) *models.Playlist {
|
|
playlist := &models.Playlist{
|
|
UserID: userID,
|
|
Title: "Original Playlist",
|
|
Description: "Test playlist",
|
|
IsPublic: false,
|
|
TrackCount: 0,
|
|
}
|
|
err := db.Create(playlist).Error
|
|
require.NoError(t, err)
|
|
|
|
tracks := make([]uuid.UUID, trackCount)
|
|
for i := 0; i < trackCount; i++ {
|
|
tracks[i] = createTestTrack(t, db, userID)
|
|
}
|
|
|
|
// Ajouter les tracks à la playlist
|
|
for i, trackID := range tracks {
|
|
playlistTrack := &models.PlaylistTrack{
|
|
PlaylistID: playlist.ID,
|
|
TrackID: trackID,
|
|
Position: i + 1,
|
|
AddedBy: userID,
|
|
}
|
|
err := db.Create(playlistTrack).Error
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Mettre à jour le compteur
|
|
playlist.TrackCount = trackCount
|
|
db.Model(playlist).Update("track_count", trackCount)
|
|
|
|
return playlist
|
|
}
|
|
|
|
// TestDuplicatePlaylist_Success vérifie que la duplication fonctionne correctement
|
|
func TestDuplicatePlaylist_Success(t *testing.T) {
|
|
db := setupTestDBForPlaylist(t)
|
|
defer cleanupTestDBForPlaylist(t, db)
|
|
|
|
logger := zaptest.NewLogger(t)
|
|
// Create repositories
|
|
playlistRepo := repositories.NewPlaylistRepository(db)
|
|
playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
|
|
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
|
|
userRepo := repositories.NewGormUserRepository(db)
|
|
|
|
playlistService := services.NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
|
|
duplicateService := services.NewPlaylistDuplicateService(playlistService, db, logger)
|
|
|
|
user := createTestUserForPlaylist(t, db)
|
|
originalPlaylist := createTestPlaylistWithTracks(t, db, user.ID, 5)
|
|
|
|
// Dupliquer la playlist
|
|
request := services.DuplicatePlaylistRequest{
|
|
NewTitle: "Duplicated Playlist",
|
|
}
|
|
newPlaylist, err := duplicateService.DuplicatePlaylist(
|
|
context.Background(),
|
|
originalPlaylist.ID,
|
|
user.ID,
|
|
request,
|
|
)
|
|
require.NoError(t, err, "DuplicatePlaylist should succeed")
|
|
require.NotNil(t, newPlaylist, "New playlist should be created")
|
|
|
|
// Vérifier que la nouvelle playlist existe
|
|
var playlistCount int64
|
|
db.Model(&models.Playlist{}).Where("id = ?", newPlaylist.ID).Count(&playlistCount)
|
|
assert.Equal(t, int64(1), playlistCount, "New playlist should exist")
|
|
|
|
// Vérifier que tous les tracks sont dupliqués
|
|
var trackCount int64
|
|
db.Model(&models.PlaylistTrack{}).
|
|
Where("playlist_id = ?", newPlaylist.ID).
|
|
Count(&trackCount)
|
|
assert.Equal(t, int64(5), trackCount, "All tracks should be duplicated")
|
|
|
|
// Vérifier que le compteur est cohérent
|
|
assert.Equal(t, int(5), newPlaylist.TrackCount, "Track count should match")
|
|
}
|
|
|
|
// TestDuplicatePlaylist_RollbackOnPlaylistNotFound vérifie le rollback si la playlist n'existe pas
|
|
func TestDuplicatePlaylist_RollbackOnPlaylistNotFound(t *testing.T) {
|
|
db := setupTestDBForPlaylist(t)
|
|
defer cleanupTestDBForPlaylist(t, db)
|
|
|
|
logger := zaptest.NewLogger(t)
|
|
// Create repositories
|
|
playlistRepo := repositories.NewPlaylistRepository(db)
|
|
playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
|
|
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
|
|
userRepo := repositories.NewGormUserRepository(db)
|
|
|
|
playlistService := services.NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
|
|
duplicateService := services.NewPlaylistDuplicateService(playlistService, db, logger)
|
|
|
|
user := createTestUserForPlaylist(t, db)
|
|
fakePlaylistID := uuid.New()
|
|
|
|
request := services.DuplicatePlaylistRequest{
|
|
NewTitle: "Duplicated Playlist",
|
|
}
|
|
_, err := duplicateService.DuplicatePlaylist(
|
|
context.Background(),
|
|
fakePlaylistID,
|
|
user.ID,
|
|
request,
|
|
)
|
|
require.Error(t, err, "DuplicatePlaylist should fail")
|
|
assert.Contains(t, err.Error(), "playlist not found", "Error should mention playlist not found")
|
|
|
|
// Vérifier qu'aucune playlist n'a été créée
|
|
var playlistCount int64
|
|
db.Model(&models.Playlist{}).Where("user_id = ?", user.ID).Count(&playlistCount)
|
|
assert.Equal(t, int64(0), playlistCount, "No playlist should be created on error")
|
|
}
|
|
|
|
// TestDuplicatePlaylist_RollbackOnTrackError vérifie le rollback si un track échoue
|
|
func TestDuplicatePlaylist_RollbackOnTrackError(t *testing.T) {
|
|
db := setupTestDBForPlaylist(t)
|
|
defer cleanupTestDBForPlaylist(t, db)
|
|
|
|
logger := zaptest.NewLogger(t)
|
|
// Create repositories
|
|
playlistRepo := repositories.NewPlaylistRepository(db)
|
|
playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
|
|
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
|
|
userRepo := repositories.NewGormUserRepository(db)
|
|
|
|
playlistService := services.NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
|
|
duplicateService := services.NewPlaylistDuplicateService(playlistService, db, logger)
|
|
|
|
user := createTestUserForPlaylist(t, db)
|
|
originalPlaylist := createTestPlaylistWithTracks(t, db, user.ID, 3)
|
|
|
|
// Supprimer un track pour forcer une erreur FK lors de la duplication
|
|
// (simulation d'une erreur au milieu de la transaction)
|
|
var firstTrack models.Track
|
|
db.Model(&models.PlaylistTrack{}).
|
|
Where("playlist_id = ?", originalPlaylist.ID).
|
|
Order("position ASC").
|
|
Limit(1).
|
|
First(&models.PlaylistTrack{}).
|
|
Association("Track").Find(&firstTrack)
|
|
|
|
// Supprimer le track
|
|
db.Delete(&firstTrack)
|
|
|
|
// Tenter de dupliquer (devrait échouer car le track n'existe plus)
|
|
request := services.DuplicatePlaylistRequest{
|
|
NewTitle: "Duplicated Playlist",
|
|
}
|
|
_, err := duplicateService.DuplicatePlaylist(
|
|
context.Background(),
|
|
originalPlaylist.ID,
|
|
user.ID,
|
|
request,
|
|
)
|
|
require.Error(t, err, "DuplicatePlaylist should fail")
|
|
|
|
// Vérifier qu'aucune playlist n'a été créée (rollback complet)
|
|
var playlistCount int64
|
|
db.Model(&models.Playlist{}).
|
|
Where("user_id = ? AND title = ?", user.ID, "Duplicated Playlist").
|
|
Count(&playlistCount)
|
|
assert.Equal(t, int64(0), playlistCount, "No playlist should be created on error")
|
|
|
|
// Vérifier qu'aucun track n'a été ajouté
|
|
var trackCount int64
|
|
db.Model(&models.PlaylistTrack{}).
|
|
Where("playlist_id != ?", originalPlaylist.ID).
|
|
Count(&trackCount)
|
|
assert.Equal(t, int64(0), trackCount, "No tracks should be created on error")
|
|
}
|
|
|
|
// TestDuplicatePlaylist_Coherence vérifie la cohérence des données après duplication
|
|
func TestDuplicatePlaylist_Coherence(t *testing.T) {
|
|
db := setupTestDBForPlaylist(t)
|
|
defer cleanupTestDBForPlaylist(t, db)
|
|
|
|
logger := zaptest.NewLogger(t)
|
|
// Create repositories
|
|
playlistRepo := repositories.NewPlaylistRepository(db)
|
|
playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
|
|
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
|
|
userRepo := repositories.NewGormUserRepository(db)
|
|
|
|
playlistService := services.NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
|
|
duplicateService := services.NewPlaylistDuplicateService(playlistService, db, logger)
|
|
|
|
user := createTestUserForPlaylist(t, db)
|
|
originalPlaylist := createTestPlaylistWithTracks(t, db, user.ID, 10)
|
|
|
|
// Dupliquer
|
|
request := services.DuplicatePlaylistRequest{
|
|
NewTitle: "Duplicated Playlist",
|
|
}
|
|
newPlaylist, err := duplicateService.DuplicatePlaylist(
|
|
context.Background(),
|
|
originalPlaylist.ID,
|
|
user.ID,
|
|
request,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Vérifier que le compteur correspond au nombre réel de tracks
|
|
var actualTrackCount int64
|
|
db.Model(&models.PlaylistTrack{}).
|
|
Where("playlist_id = ?", newPlaylist.ID).
|
|
Count(&actualTrackCount)
|
|
assert.Equal(t, int64(newPlaylist.TrackCount), actualTrackCount, "Track count should match actual tracks")
|
|
|
|
// Vérifier que les positions sont cohérentes
|
|
var playlistTracks []models.PlaylistTrack
|
|
db.Where("playlist_id = ?", newPlaylist.ID).
|
|
Order("position ASC").
|
|
Find(&playlistTracks)
|
|
|
|
for i, pt := range playlistTracks {
|
|
assert.Equal(t, i+1, pt.Position, "Position should be sequential")
|
|
}
|
|
}
|
|
|
|
// TestDuplicatePlaylist_EmptyPlaylist vérifie la duplication d'une playlist vide
|
|
func TestDuplicatePlaylist_EmptyPlaylist(t *testing.T) {
|
|
db := setupTestDBForPlaylist(t)
|
|
defer cleanupTestDBForPlaylist(t, db)
|
|
|
|
logger := zaptest.NewLogger(t)
|
|
// Create repositories
|
|
playlistRepo := repositories.NewPlaylistRepository(db)
|
|
playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
|
|
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
|
|
userRepo := repositories.NewGormUserRepository(db)
|
|
|
|
playlistService := services.NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
|
|
duplicateService := services.NewPlaylistDuplicateService(playlistService, db, logger)
|
|
|
|
user := createTestUserForPlaylist(t, db)
|
|
originalPlaylist := createTestPlaylistWithTracks(t, db, user.ID, 0) // Playlist vide
|
|
|
|
request := services.DuplicatePlaylistRequest{
|
|
NewTitle: "Duplicated Empty Playlist",
|
|
}
|
|
newPlaylist, err := duplicateService.DuplicatePlaylist(
|
|
context.Background(),
|
|
originalPlaylist.ID,
|
|
user.ID,
|
|
request,
|
|
)
|
|
require.NoError(t, err, "Duplicating empty playlist should succeed")
|
|
assert.Equal(t, 0, newPlaylist.TrackCount, "Empty playlist should have 0 tracks")
|
|
|
|
// Vérifier qu'aucun track n'a été créé
|
|
var trackCount int64
|
|
db.Model(&models.PlaylistTrack{}).
|
|
Where("playlist_id = ?", newPlaylist.ID).
|
|
Count(&trackCount)
|
|
assert.Equal(t, int64(0), trackCount, "No tracks should be created for empty playlist")
|
|
}
|