package services import ( "context" "errors" "testing" "time" "github.com/google/uuid" "veza-backend-api/internal/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/sqlite" "gorm.io/gorm" ) func setupTestTrackShareService(t *testing.T) (*TrackShareService, *gorm.DB, uuid.UUID, func()) { // Setup in-memory SQLite database db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err) // Auto-migrate err = db.AutoMigrate(&models.TrackShare{}, &models.Track{}, &models.User{}) require.NoError(t, err) // Create test user userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } err = db.Create(user).Error require.NoError(t, err) // Setup service // TrackShareService might need logger too? // The original test didn't pass one, assuming NewTrackShareService(db) only. // Checking the file content, it was: NewTrackShareService(db) service := NewTrackShareService(db) // Cleanup function cleanup := func() { // Database will be closed automatically } return service, db, userID, cleanup } func TestTrackShareService_CreateShare(t *testing.T) { service, db, userID, cleanup := setupTestTrackShareService(t) defer cleanup() ctx := context.Background() // Create test track track := &models.Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error require.NoError(t, err) // Create share share, err := service.CreateShare(ctx, track.ID, userID, "read,download", nil) assert.NoError(t, err) assert.NotNil(t, share) assert.Equal(t, track.ID, share.TrackID) assert.Equal(t, userID, share.UserID) assert.Equal(t, "read,download", share.Permissions) assert.NotEmpty(t, share.ShareToken) } func TestTrackShareService_CreateShare_NotOwner(t *testing.T) { service, db, userID, cleanup := setupTestTrackShareService(t) defer cleanup() ctx := context.Background() // Create test track track := &models.Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error require.NoError(t, err) // Try to create share as different user share, err := service.CreateShare(ctx, track.ID, uuid.New(), "read,download", nil) assert.Error(t, err) assert.Nil(t, share) assert.Equal(t, ErrForbidden, err) } func TestTrackShareService_ValidateShareToken(t *testing.T) { service, db, userID, cleanup := setupTestTrackShareService(t) defer cleanup() ctx := context.Background() // Create test track track := &models.Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error require.NoError(t, err) // Create share share, err := service.CreateShare(ctx, track.ID, userID, "read,download", nil) require.NoError(t, err) // Validate token validatedShare, err := service.ValidateShareToken(ctx, share.ShareToken) assert.NoError(t, err) assert.NotNil(t, validatedShare) assert.Equal(t, share.ID, validatedShare.ID) assert.Equal(t, int64(1), validatedShare.AccessCount) // Should be incremented } func TestTrackShareService_ValidateShareToken_Expired(t *testing.T) { service, db, userID, cleanup := setupTestTrackShareService(t) defer cleanup() ctx := context.Background() // Create test track track := &models.Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error require.NoError(t, err) // Create share with expiration in the past expiredTime := time.Now().Add(-1 * time.Hour) share := &models.TrackShare{ TrackID: track.ID, UserID: userID, ShareToken: "test-token-123", Permissions: "read,download", ExpiresAt: &expiredTime, AccessCount: 0, } err = db.Create(share).Error require.NoError(t, err) // Try to validate expired token validatedShare, err := service.ValidateShareToken(ctx, share.ShareToken) assert.Error(t, err) assert.Nil(t, validatedShare) assert.Equal(t, ErrShareExpired, err) } func TestTrackShareService_CheckPermission(t *testing.T) { service, _, _, cleanup := setupTestTrackShareService(t) defer cleanup() // Test with read permission share := &models.TrackShare{ Permissions: "read", ExpiresAt: nil, } assert.True(t, service.CheckPermission(share, "read")) assert.False(t, service.CheckPermission(share, "download")) // Test with download permission share.Permissions = "download" assert.False(t, service.CheckPermission(share, "read")) assert.True(t, service.CheckPermission(share, "download")) // Test with both permissions share.Permissions = "read,download" assert.True(t, service.CheckPermission(share, "read")) assert.True(t, service.CheckPermission(share, "download")) // Test with expired share expiredTime := time.Now().Add(-1 * time.Hour) share.ExpiresAt = &expiredTime assert.False(t, service.CheckPermission(share, "read")) assert.False(t, service.CheckPermission(share, "download")) } func TestTrackShareService_RevokeShare(t *testing.T) { service, db, userID, cleanup := setupTestTrackShareService(t) defer cleanup() ctx := context.Background() // Create test track track := &models.Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error require.NoError(t, err) // Create share share, err := service.CreateShare(ctx, track.ID, userID, "read,download", nil) require.NoError(t, err) // Revoke share err = service.RevokeShare(ctx, share.ID, userID) assert.NoError(t, err) // Verify share is deleted var deletedShare models.TrackShare err = db.First(&deletedShare, "id = ?", share.ID).Error assert.Error(t, err) assert.True(t, errors.Is(err, gorm.ErrRecordNotFound)) }