veza/veza-backend-api/internal/testutils/fixtures.go
2025-12-16 11:23:49 -05:00

492 lines
13 KiB
Go

package testutils
import (
"fmt"
"strings"
"time"
"veza-backend-api/internal/models"
"github.com/google/uuid"
"gorm.io/gorm"
)
// CreateTestUser crée un utilisateur de test avec des valeurs par défaut
func CreateTestUser(db *gorm.DB) (*models.User, error) {
// Make username and email unique to avoid constraint violations when tests share the same DB
uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "")
uniqueUsername := fmt.Sprintf("testuser_%s", uniqueID)
uniqueEmail := fmt.Sprintf("test_%s@example.com", uniqueID)
// Slug must also be unique - use the same uniqueID to ensure uniqueness
uniqueSlug := fmt.Sprintf("testuser-%s", uniqueID)
user := &models.User{
Username: uniqueUsername,
Slug: uniqueSlug,
Email: uniqueEmail,
PasswordHash: "$2a$10$examplehash", // Hash bcrypt factice
TokenVersion: 0,
FirstName: "Test",
LastName: "User",
Role: "user",
IsActive: true,
IsVerified: true,
IsAdmin: false,
}
if err := db.Create(user).Error; err != nil {
return nil, err
}
return user, nil
}
// CreateTestUserWithCustomData crée un utilisateur de test avec des données personnalisées
func CreateTestUserWithCustomData(db *gorm.DB, username, email string) (*models.User, error) {
// Make username and email unique to avoid constraint violations
// Username must match ^[a-zA-Z0-9_]{3,30}$ (no dashes, only alphanum + underscore)
uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "") // Remove dashes from UUID
// Ensure username doesn't exceed 30 chars (constraint limit)
maxUsernameLen := 30
uniqueUsername := fmt.Sprintf("%s_%s", username, uniqueID)
if len(uniqueUsername) > maxUsernameLen {
// Truncate username part if needed
maxUsernamePartLen := maxUsernameLen - len(uniqueID) - 1 // -1 for underscore
if maxUsernamePartLen < 1 {
maxUsernamePartLen = 1
}
uniqueUsername = fmt.Sprintf("%s_%s", username[:maxUsernamePartLen], uniqueID)
}
// Extract email parts and add unique ID
emailParts := strings.Split(email, "@")
if len(emailParts) != 2 {
return nil, fmt.Errorf("invalid email format: %s", email)
}
uniqueEmail := fmt.Sprintf("%s_%s@%s", emailParts[0], uniqueID, emailParts[1])
// Slug must also be unique - generate from username with uniqueID
// Slugify converts underscores to dashes, so "customuser_abc123" becomes "customuser-abc123"
uniqueSlug := fmt.Sprintf("%s-%s", strings.ToLower(username), uniqueID)
user := &models.User{
Username: uniqueUsername,
Slug: uniqueSlug,
Email: uniqueEmail,
PasswordHash: "$2a$10$examplehash",
TokenVersion: 0,
FirstName: "Test",
LastName: "User",
Role: "user",
IsActive: true,
IsVerified: true,
IsAdmin: false,
}
if err := db.Create(user).Error; err != nil {
return nil, err
}
return user, nil
}
// CreateTestAdmin crée un utilisateur administrateur de test
func CreateTestAdmin(db *gorm.DB) (*models.User, error) {
// Make username and email unique to avoid constraint violations when tests share the same DB
uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "")
uniqueUsername := fmt.Sprintf("admin_%s", uniqueID)
uniqueEmail := fmt.Sprintf("admin_%s@example.com", uniqueID)
// Slug must also be unique - use the same uniqueID to ensure uniqueness
uniqueSlug := fmt.Sprintf("admin-%s", uniqueID)
user := &models.User{
Username: uniqueUsername,
Slug: uniqueSlug,
Email: uniqueEmail,
PasswordHash: "$2a$10$examplehash",
TokenVersion: 0,
FirstName: "Admin",
LastName: "User",
Role: "admin",
IsActive: true,
IsVerified: true,
IsAdmin: true,
}
if err := db.Create(user).Error; err != nil {
return nil, err
}
return user, nil
}
// CreateTestTrack crée un track de test
func CreateTestTrack(db *gorm.DB, userID uuid.UUID) (*models.Track, error) {
track := &models.Track{
UserID: userID,
Title: "Test Track",
Artist: "Test Artist",
Duration: 180, // 3 minutes
FilePath: "uploads/test_track.mp3",
FileSize: 1024 * 1024 * 5, // 5MB
Format: "mp3",
}
if err := db.Create(track).Error; err != nil {
return nil, err
}
return track, nil
}
// CreateTestTrackWithCustomData crée un track de test avec des données personnalisées
func CreateTestTrackWithCustomData(db *gorm.DB, userID uuid.UUID, title, artist string) (*models.Track, error) {
track := &models.Track{
UserID: userID,
Title: title,
Artist: artist,
Duration: 180,
FilePath: "uploads/test_track.mp3",
FileSize: 1024 * 1024 * 5,
Format: "mp3",
}
if err := db.Create(track).Error; err != nil {
return nil, err
}
return track, nil
}
// CreateTestPlaylist crée une playlist de test
func CreateTestPlaylist(db *gorm.DB, userID uuid.UUID) (*models.Playlist, error) {
playlist := &models.Playlist{
UserID: userID,
Title: "Test Playlist",
Description: "A test playlist",
}
if err := db.Create(playlist).Error; err != nil {
return nil, err
}
return playlist, nil
}
// CreateTestRoom crée une room de test
func CreateTestRoom(db *gorm.DB, createdBy uuid.UUID) (*models.Room, error) {
room := &models.Room{
Name: "Test Room",
Description: "A test room",
Type: "public",
IsPrivate: false,
CreatedBy: createdBy,
}
if err := db.Create(room).Error; err != nil {
return nil, err
}
return room, nil
}
// CreateTestMessage crée un message de test
func CreateTestMessage(db *gorm.DB, roomID uuid.UUID, userID uuid.UUID, content string) (*models.Message, error) {
message := &models.Message{
RoomID: roomID,
UserID: userID,
Content: content,
Type: "text",
IsEdited: false,
IsDeleted: false,
}
if err := db.Create(message).Error; err != nil {
return nil, err
}
return message, nil
}
// CreateTestSession crée une session de test
func CreateTestSession(db *gorm.DB, userID uuid.UUID) (*models.Session, error) {
session := &models.Session{
UserID: userID,
Token: "test_hash_" + uuid.New().String(),
IPAddress: "127.0.0.1",
UserAgent: "test-agent",
ExpiresAt: time.Now().Add(24 * time.Hour),
}
if err := db.Create(session).Error; err != nil {
return nil, err
}
return session, nil
}
// CreateMultipleTestUsers crée plusieurs utilisateurs de test
func CreateMultipleTestUsers(db *gorm.DB, count int) ([]*models.User, error) {
users := make([]*models.User, 0, count)
for i := 1; i <= count; i++ {
// Make username and email unique to avoid constraint violations when tests share the same DB
uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "")
uniqueUsername := fmt.Sprintf("testuser%d_%s", i, uniqueID)
uniqueEmail := fmt.Sprintf("test%d_%s@example.com", i, uniqueID)
uniqueSlug := fmt.Sprintf("testuser%d-%s", i, uniqueID)
user := &models.User{
Username: uniqueUsername,
Slug: uniqueSlug,
Email: uniqueEmail,
PasswordHash: "$2a$10$examplehash",
TokenVersion: 0,
FirstName: "Test",
LastName: "User",
Role: "user",
IsActive: true,
IsVerified: true,
IsAdmin: false,
}
if err := db.Create(user).Error; err != nil {
return nil, err
}
users = append(users, user)
}
return users, nil
}
// CreateMultipleTestTracks crée plusieurs tracks de test pour un créateur
func CreateMultipleTestTracks(db *gorm.DB, userID uuid.UUID, count int) ([]*models.Track, error) {
tracks := make([]*models.Track, 0, count)
for i := 1; i <= count; i++ {
track := &models.Track{
UserID: userID,
Title: fmt.Sprintf("Test Track %d", i),
Artist: "Test Artist",
Duration: 180,
FilePath: "uploads/test_track.mp3",
FileSize: 1024 * 1024,
Format: "mp3",
}
if err := db.Create(track).Error; err != nil {
return nil, err
}
tracks = append(tracks, track)
}
return tracks, nil
}
// UserFactory crée des utilisateurs de test avec pattern Builder
type UserFactory struct {
user *models.User
}
// NewUserFactory crée un nouveau factory avec valeurs par défaut
func NewUserFactory() *UserFactory {
return &UserFactory{
user: &models.User{
Username: "testuser",
Email: "test@example.com",
PasswordHash: "$2a$10$examplehash",
TokenVersion: 0,
FirstName: "Test",
LastName: "User",
Role: "user",
IsActive: true,
IsVerified: true,
IsAdmin: false,
},
}
}
// WithUsername définit le username
func (f *UserFactory) WithUsername(username string) *UserFactory {
f.user.Username = username
return f
}
// WithEmail définit l'email
func (f *UserFactory) WithEmail(email string) *UserFactory {
f.user.Email = email
return f
}
// WithRole définit le rôle
func (f *UserFactory) WithRole(role string) *UserFactory {
f.user.Role = role
if role == "admin" {
f.user.IsAdmin = true
}
return f
}
// WithPasswordHash définit le hash du mot de passe
func (f *UserFactory) WithPasswordHash(hash string) *UserFactory {
f.user.PasswordHash = hash
return f
}
// WithFirstName définit le prénom
func (f *UserFactory) WithFirstName(firstName string) *UserFactory {
f.user.FirstName = firstName
return f
}
// WithLastName définit le nom
func (f *UserFactory) WithLastName(lastName string) *UserFactory {
f.user.LastName = lastName
return f
}
// WithIsActive définit si l'utilisateur est actif
func (f *UserFactory) WithIsActive(isActive bool) *UserFactory {
f.user.IsActive = isActive
return f
}
// WithIsVerified définit si l'utilisateur est vérifié
func (f *UserFactory) WithIsVerified(isVerified bool) *UserFactory {
f.user.IsVerified = isVerified
return f
}
// Build construit l'utilisateur sans sauvegarder
func (f *UserFactory) Build() *models.User {
return f.user
}
// MustBuild construit et sauvegarde en DB
func (f *UserFactory) MustBuild(db *gorm.DB) *models.User {
user := f.Build()
if err := db.Create(user).Error; err != nil {
panic(err)
}
return user
}
// TrackFactory crée des tracks de test avec pattern Builder
type TrackFactory struct {
track *models.Track
}
// NewTrackFactory crée un nouveau factory avec valeurs par défaut
func NewTrackFactory(userID uuid.UUID) *TrackFactory {
return &TrackFactory{
track: &models.Track{
UserID: userID,
Title: "Test Track",
Artist: "Test Artist",
Duration: 180, // 3 minutes
FilePath: "uploads/test_track.mp3",
FileSize: 1024 * 1024,
Format: "mp3",
},
}
}
// WithTitle définit le titre
func (f *TrackFactory) WithTitle(title string) *TrackFactory {
f.track.Title = title
return f
}
// WithArtist définit l'artiste
func (f *TrackFactory) WithArtist(artist string) *TrackFactory {
f.track.Artist = artist
return f
}
// WithDuration définit la durée en secondes
func (f *TrackFactory) WithDuration(duration int) *TrackFactory {
f.track.Duration = duration
return f
}
// Build construit le track sans sauvegarder
func (f *TrackFactory) Build() *models.Track {
return f.track
}
// MustBuild construit et sauvegarde en DB
func (f *TrackFactory) MustBuild(db *gorm.DB) *models.Track {
track := f.Build()
if err := db.Create(track).Error; err != nil {
panic(err)
}
return track
}
// PlaylistFactory crée des playlists de test avec pattern Builder
type PlaylistFactory struct {
playlist *models.Playlist
}
// NewPlaylistFactory crée un nouveau factory avec valeurs par défaut
func NewPlaylistFactory(userID uuid.UUID) *PlaylistFactory {
return &PlaylistFactory{
playlist: &models.Playlist{
UserID: userID,
Title: "Test Playlist",
Description: "A test playlist",
},
}
}
// WithName définit le titre (Mapped to Title)
func (f *PlaylistFactory) WithName(name string) *PlaylistFactory {
f.playlist.Title = name
return f
}
// WithDescription définit la description
func (f *PlaylistFactory) WithDescription(description string) *PlaylistFactory {
f.playlist.Description = description
return f
}
// Build construit la playlist sans sauvegarder
func (f *PlaylistFactory) Build() *models.Playlist {
return f.playlist
}
// MustBuild construit et sauvegarde en DB
func (f *PlaylistFactory) MustBuild(db *gorm.DB) *models.Playlist {
playlist := f.Build()
if err := db.Create(playlist).Error; err != nil {
panic(err)
}
return playlist
}
// CreateUsers crée N utilisateurs avec factories
func CreateUsers(db *gorm.DB, count int) []*models.User {
users := make([]*models.User, count)
for i := 0; i < count; i++ {
factory := NewUserFactory().
WithUsername(fmt.Sprintf("user%d", i)).
WithEmail(fmt.Sprintf("user%d@example.com", i))
users[i] = factory.MustBuild(db)
}
return users
}
// CreateTracks crée N tracks avec factories
func CreateTracks(db *gorm.DB, userID uuid.UUID, count int) []*models.Track {
tracks := make([]*models.Track, count)
for i := 0; i < count; i++ {
factory := NewTrackFactory(userID).
WithTitle(fmt.Sprintf("Test Track %d", i+1)).
WithArtist(fmt.Sprintf("Test Artist %d", i+1))
tracks[i] = factory.MustBuild(db)
}
return tracks
}