package services import ( "context" "github.com/google/uuid" "testing" "github.com/stretchr/testify/assert" "go.uber.org/zap" "gorm.io/driver/sqlite" "gorm.io/gorm" "veza-backend-api/internal/models" ) func setupTestTrackUploadService(t *testing.T) (*TrackUploadService, *gorm.DB, func()) { // Setup in-memory SQLite database db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) assert.NoError(t, err) // Auto-migrate err = db.AutoMigrate(&models.Track{}) assert.NoError(t, err) // Create test service logger := zap.NewNop() service := NewTrackUploadService(db, logger) // Cleanup function cleanup := func() { // Database will be closed automatically } return service, db, cleanup } func TestTrackUploadService_GetUploadProgress_Success(t *testing.T) { service, db, cleanup := setupTestTrackUploadService(t) defer cleanup() // Create test track track := &models.Track{ UserID: uuid.New(), Title: "Test Track", FilePath: "/uploads/tracks/test.mp3", FileSize: 1024, Format: "MP3", Duration: 180, Status: models.TrackStatusProcessing, StatusMessage: "Processing audio metadata", IsPublic: true, } err := db.Create(track).Error assert.NoError(t, err) // Get progress ctx := context.Background() progress, err := service.GetUploadProgress(ctx, track.ID) // Assert assert.NoError(t, err) assert.NotNil(t, progress) assert.Equal(t, track.ID, progress.TrackID) assert.Equal(t, models.TrackStatusProcessing, progress.Status) assert.Equal(t, 50, progress.Progress) // Processing = 50% assert.Equal(t, "Processing audio metadata", progress.Message) } func TestTrackUploadService_GetUploadProgress_NotFound(t *testing.T) { service, _, cleanup := setupTestTrackUploadService(t) defer cleanup() // Get progress for non-existent track ctx := context.Background() progress, err := service.GetUploadProgress(ctx, uuid.New()) // Assert assert.Error(t, err) assert.Nil(t, progress) assert.Contains(t, err.Error(), "track not found") } func TestTrackUploadService_GetUploadProgress_AllStatuses(t *testing.T) { service, db, cleanup := setupTestTrackUploadService(t) defer cleanup() statuses := []struct { status models.TrackStatus expected int }{ {models.TrackStatusUploading, 25}, {models.TrackStatusProcessing, 50}, {models.TrackStatusCompleted, 100}, {models.TrackStatusFailed, 0}, } ctx := context.Background() for i, tt := range statuses { // Create test track track := &models.Track{ UserID: uuid.New(), Title: "Test Track", FilePath: "/uploads/tracks/test.mp3", FileSize: 1024, Format: "MP3", Duration: 180, Status: tt.status, IsPublic: true, } err := db.Create(track).Error assert.NoError(t, err) // Get progress progress, err := service.GetUploadProgress(ctx, track.ID) assert.NoError(t, err, "status: %s", tt.status) assert.NotNil(t, progress) assert.Equal(t, tt.expected, progress.Progress, "status: %s, index: %d", tt.status, i) assert.Equal(t, tt.status, progress.Status) } } func TestTrackUploadService_UpdateUploadStatus_Success(t *testing.T) { service, db, cleanup := setupTestTrackUploadService(t) defer cleanup() // Create test track track := &models.Track{ UserID: uuid.New(), Title: "Test Track", FilePath: "/uploads/tracks/test.mp3", FileSize: 1024, Format: "MP3", Duration: 180, Status: models.TrackStatusUploading, IsPublic: true, } err := db.Create(track).Error assert.NoError(t, err) // Update status ctx := context.Background() err = service.UpdateUploadStatus(ctx, track.ID, models.TrackStatusProcessing, "Processing metadata") assert.NoError(t, err) // Verify update var updatedTrack models.Track err = db.First(&updatedTrack, track.ID).Error assert.NoError(t, err) assert.Equal(t, models.TrackStatusProcessing, updatedTrack.Status) assert.Equal(t, "Processing metadata", updatedTrack.StatusMessage) } func TestTrackUploadService_UpdateUploadStatus_WithoutMessage(t *testing.T) { service, db, cleanup := setupTestTrackUploadService(t) defer cleanup() // Create test track with message track := &models.Track{ UserID: uuid.New(), Title: "Test Track", FilePath: "/uploads/tracks/test.mp3", FileSize: 1024, Format: "MP3", Duration: 180, Status: models.TrackStatusProcessing, StatusMessage: "Previous message", IsPublic: true, } err := db.Create(track).Error assert.NoError(t, err) // Update status without message (should preserve existing message) ctx := context.Background() err = service.UpdateUploadStatus(ctx, track.ID, models.TrackStatusCompleted, "") assert.NoError(t, err) // Verify update var updatedTrack models.Track err = db.First(&updatedTrack, track.ID).Error assert.NoError(t, err) assert.Equal(t, models.TrackStatusCompleted, updatedTrack.Status) // Message should be preserved or cleared depending on implementation } func TestTrackUploadService_UpdateUploadStatus_WithMessage(t *testing.T) { service, db, cleanup := setupTestTrackUploadService(t) defer cleanup() // Create test track track := &models.Track{ UserID: uuid.New(), Title: "Test Track", FilePath: "/uploads/tracks/test.mp3", FileSize: 1024, Format: "MP3", Duration: 180, Status: models.TrackStatusUploading, IsPublic: true, } err := db.Create(track).Error assert.NoError(t, err) // Update status with message ctx := context.Background() err = service.UpdateUploadStatus(ctx, track.ID, models.TrackStatusFailed, "Upload failed: connection timeout") assert.NoError(t, err) // Verify update var updatedTrack models.Track err = db.First(&updatedTrack, track.ID).Error assert.NoError(t, err) assert.Equal(t, models.TrackStatusFailed, updatedTrack.Status) assert.Equal(t, "Upload failed: connection timeout", updatedTrack.StatusMessage) } func TestTrackUploadService_CalculateProgress(t *testing.T) { service, _, cleanup := setupTestTrackUploadService(t) defer cleanup() tests := []struct { status models.TrackStatus expected int }{ {models.TrackStatusUploading, 25}, {models.TrackStatusProcessing, 50}, {models.TrackStatusCompleted, 100}, {models.TrackStatusFailed, 0}, } for _, tt := range tests { t.Run(string(tt.status), func(t *testing.T) { progress := service.calculateProgress(tt.status) assert.Equal(t, tt.expected, progress) }) } } func TestTrackUploadService_UpdateUploadStatus_AllStatuses(t *testing.T) { service, db, cleanup := setupTestTrackUploadService(t) defer cleanup() statuses := []models.TrackStatus{ models.TrackStatusUploading, models.TrackStatusProcessing, models.TrackStatusCompleted, models.TrackStatusFailed, } ctx := context.Background() for _, status := range statuses { // Create test track track := &models.Track{ UserID: uuid.New(), Title: "Test Track", FilePath: "/uploads/tracks/test.mp3", FileSize: 1024, Format: "MP3", Duration: 180, Status: models.TrackStatusUploading, IsPublic: true, } err := db.Create(track).Error assert.NoError(t, err) // Update status err = service.UpdateUploadStatus(ctx, track.ID, status, "Status updated") assert.NoError(t, err, "Failed to update status: %s", status) // Verify var updatedTrack models.Track err = db.First(&updatedTrack, track.ID).Error assert.NoError(t, err) assert.Equal(t, status, updatedTrack.Status) } }