303 lines
7.1 KiB
Text
303 lines
7.1 KiB
Text
package services
|
|
|
|
import (
|
|
"context"
|
|
"github.com/google/uuid"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"veza-backend-api/internal/models"
|
|
)
|
|
|
|
func setupTestTrackStatsDB(t *testing.T) (*TrackService, *gorm.DB, 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.User{},
|
|
&models.Track{},
|
|
&models.TrackLike{},
|
|
&models.TrackComment{},
|
|
&models.TrackPlay{},
|
|
&models.TrackShare{},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Create test user
|
|
user := &models.User{
|
|
ID: 1,
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
IsActive: true,
|
|
}
|
|
err = db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create logger
|
|
logger := zap.NewNop()
|
|
|
|
// Create service
|
|
service := NewTrackService(db, logger, "test_uploads")
|
|
|
|
// Cleanup function
|
|
cleanup := func() {
|
|
// SQLite in-memory database doesn't need explicit cleanup
|
|
}
|
|
|
|
return service, db, cleanup
|
|
}
|
|
|
|
func TestTrackService_GetTrackStats_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestTrackStatsDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a track
|
|
track := &models.Track{
|
|
UserID: 1,
|
|
Title: "Test Track",
|
|
FilePath: "/path/to/track.mp3",
|
|
FileSize: 1024,
|
|
Format: "MP3",
|
|
Duration: 180,
|
|
IsPublic: true,
|
|
Status: models.TrackStatusCompleted,
|
|
}
|
|
err := db.Create(track).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create some likes
|
|
like1 := &models.TrackLike{UserID: 1, TrackID: track.ID}
|
|
like2 := &models.TrackLike{UserID: 2, TrackID: track.ID}
|
|
err = db.Create(like1).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(like2).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create some comments
|
|
comment1 := &models.TrackComment{
|
|
TrackID: track.ID,
|
|
UserID: 1,
|
|
Content: "Great track!",
|
|
}
|
|
comment2 := &models.TrackComment{
|
|
TrackID: track.ID,
|
|
UserID: 2,
|
|
Content: "Love it!",
|
|
}
|
|
err = db.Create(comment1).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(comment2).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create some plays
|
|
play1 := &models.TrackPlay{
|
|
TrackID: track.ID,
|
|
UserID: &[]int64{1}[0],
|
|
Duration: 120,
|
|
PlayedAt: time.Now(),
|
|
}
|
|
play2 := &models.TrackPlay{
|
|
TrackID: track.ID,
|
|
UserID: &[]int64{2}[0],
|
|
Duration: 150,
|
|
PlayedAt: time.Now(),
|
|
}
|
|
play3 := &models.TrackPlay{
|
|
TrackID: track.ID,
|
|
UserID: nil, // Anonymous play
|
|
Duration: 60,
|
|
PlayedAt: time.Now(),
|
|
}
|
|
err = db.Create(play1).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(play2).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(play3).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create a share with download permission and access count
|
|
share := &models.TrackShare{
|
|
TrackID: track.ID,
|
|
UserID: 1,
|
|
ShareToken: "test-token",
|
|
Permissions: "read,download",
|
|
AccessCount: 5,
|
|
}
|
|
err = db.Create(share).Error
|
|
require.NoError(t, err)
|
|
|
|
// Get stats
|
|
stats, err := service.GetTrackStats(ctx, track.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, stats)
|
|
|
|
// Verify stats
|
|
assert.Equal(t, int64(3), stats.Views) // 3 plays
|
|
assert.Equal(t, int64(2), stats.Likes) // 2 likes
|
|
assert.Equal(t, int64(2), stats.Comments) // 2 comments
|
|
assert.Equal(t, int64(330), stats.TotalPlayTime) // 120 + 150 + 60 = 330 seconds
|
|
assert.Equal(t, int64(5), stats.Downloads) // 5 downloads from share
|
|
}
|
|
|
|
func TestTrackService_GetTrackStats_TrackNotFound(t *testing.T) {
|
|
service, _, cleanup := setupTestTrackStatsDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Try to get stats for non-existent track
|
|
stats, err := service.GetTrackStats(ctx, 999)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, stats)
|
|
assert.Equal(t, ErrTrackNotFound, err)
|
|
}
|
|
|
|
func TestTrackService_GetTrackStats_EmptyStats(t *testing.T) {
|
|
service, db, cleanup := setupTestTrackStatsDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a track with no interactions
|
|
track := &models.Track{
|
|
UserID: 1,
|
|
Title: "Empty Track",
|
|
FilePath: "/path/to/track.mp3",
|
|
FileSize: 1024,
|
|
Format: "MP3",
|
|
Duration: 180,
|
|
IsPublic: true,
|
|
Status: models.TrackStatusCompleted,
|
|
}
|
|
err := db.Create(track).Error
|
|
require.NoError(t, err)
|
|
|
|
// Get stats
|
|
stats, err := service.GetTrackStats(ctx, track.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, stats)
|
|
|
|
// Verify all stats are zero
|
|
assert.Equal(t, int64(0), stats.Views)
|
|
assert.Equal(t, int64(0), stats.Likes)
|
|
assert.Equal(t, int64(0), stats.Comments)
|
|
assert.Equal(t, int64(0), stats.TotalPlayTime)
|
|
assert.Equal(t, int64(0), stats.Downloads)
|
|
}
|
|
|
|
func TestTrackService_GetTrackStats_MultipleShares(t *testing.T) {
|
|
service, db, cleanup := setupTestTrackStatsDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a track
|
|
track := &models.Track{
|
|
UserID: 1,
|
|
Title: "Shared Track",
|
|
FilePath: "/path/to/track.mp3",
|
|
FileSize: 1024,
|
|
Format: "MP3",
|
|
Duration: 180,
|
|
IsPublic: true,
|
|
Status: models.TrackStatusCompleted,
|
|
}
|
|
err := db.Create(track).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create multiple shares with download permissions
|
|
share1 := &models.TrackShare{
|
|
TrackID: track.ID,
|
|
UserID: 1,
|
|
ShareToken: "token1",
|
|
Permissions: "read,download",
|
|
AccessCount: 3,
|
|
}
|
|
share2 := &models.TrackShare{
|
|
TrackID: track.ID,
|
|
UserID: 1,
|
|
ShareToken: "token2",
|
|
Permissions: "download",
|
|
AccessCount: 2,
|
|
}
|
|
share3 := &models.TrackShare{
|
|
TrackID: track.ID,
|
|
UserID: 1,
|
|
ShareToken: "token3",
|
|
Permissions: "read", // No download permission
|
|
AccessCount: 10,
|
|
}
|
|
err = db.Create(share1).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(share2).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(share3).Error
|
|
require.NoError(t, err)
|
|
|
|
// Get stats
|
|
stats, err := service.GetTrackStats(ctx, track.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, stats)
|
|
|
|
// Verify downloads count only shares with download permission
|
|
assert.Equal(t, int64(5), stats.Downloads) // 3 + 2 = 5 (share3 excluded)
|
|
}
|
|
|
|
func TestTrackService_GetTrackStats_SoftDeletedComments(t *testing.T) {
|
|
service, db, cleanup := setupTestTrackStatsDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a track
|
|
track := &models.Track{
|
|
UserID: 1,
|
|
Title: "Track with Deleted Comments",
|
|
FilePath: "/path/to/track.mp3",
|
|
FileSize: 1024,
|
|
Format: "MP3",
|
|
Duration: 180,
|
|
IsPublic: true,
|
|
Status: models.TrackStatusCompleted,
|
|
}
|
|
err := db.Create(track).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create comments
|
|
comment1 := &models.TrackComment{
|
|
TrackID: track.ID,
|
|
UserID: 1,
|
|
Content: "Comment 1",
|
|
}
|
|
comment2 := &models.TrackComment{
|
|
TrackID: track.ID,
|
|
UserID: 2,
|
|
Content: "Comment 2",
|
|
}
|
|
err = db.Create(comment1).Error
|
|
require.NoError(t, err)
|
|
err = db.Create(comment2).Error
|
|
require.NoError(t, err)
|
|
|
|
// Soft delete one comment
|
|
err = db.Delete(comment1).Error
|
|
require.NoError(t, err)
|
|
|
|
// Get stats
|
|
stats, err := service.GetTrackStats(ctx, track.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, stats)
|
|
|
|
// Verify only non-deleted comments are counted
|
|
// Note: GORM's Count by default excludes soft-deleted records
|
|
assert.Equal(t, int64(1), stats.Comments)
|
|
}
|