veza/veza-backend-api/internal/services/playlist_analytics_service_test.go

350 lines
8.6 KiB
Go

package services
import (
"context"
"github.com/google/uuid"
"testing"
"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 setupTestPlaylistAnalyticsService(t *testing.T) (*PlaylistAnalyticsService, *gorm.DB, func()) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
// Enable foreign keys for SQLite
db.Exec("PRAGMA foreign_keys = ON")
// Auto-migrate
err = db.AutoMigrate(
&models.User{},
&models.Track{},
&models.Playlist{},
&models.PlaylistTrack{},
&models.PlaylistShareLink{},
&models.PlaylistFollow{},
&models.TrackPlay{},
)
require.NoError(t, err)
logger := zap.NewNop()
service := NewPlaylistAnalyticsService(db, logger)
cleanup := func() {
// Database will be closed automatically
}
return service, db, cleanup
}
func TestPlaylistAnalyticsService_GetPlaylistStats(t *testing.T) {
service, db, cleanup := setupTestPlaylistAnalyticsService(t)
defer cleanup()
ctx := context.Background()
// Create test user
user := &models.User{
Username: "user1",
Email: "user1@example.com",
PasswordHash: "hash1",
Slug: "user1",
IsActive: true,
}
require.NoError(t, db.Create(user).Error)
// Create test tracks
track1 := &models.Track{
UserID: user.ID,
Title: "Track 1",
FilePath: "/path/to/track1.mp3",
FileSize: 1024,
Format: "MP3",
Duration: 180,
IsPublic: true,
Status: models.TrackStatusCompleted,
PlayCount: 0,
LikeCount: 0,
}
track2 := &models.Track{
UserID: user.ID,
Title: "Track 2",
FilePath: "/path/to/track2.mp3",
FileSize: 2048,
Format: "MP3",
Duration: 240,
IsPublic: true,
Status: models.TrackStatusCompleted,
PlayCount: 0,
LikeCount: 0,
}
require.NoError(t, db.Create(track1).Error)
require.NoError(t, db.Create(track2).Error)
// Create test playlist
playlist := &models.Playlist{
UserID: user.ID,
Title: "Test Playlist",
Description: "A test playlist",
IsPublic: true,
TrackCount: 2,
FollowerCount: 0,
}
require.NoError(t, db.Create(playlist).Error)
// Add tracks to playlist
playlistTrack1 := &models.PlaylistTrack{
PlaylistID: playlist.ID,
TrackID: track1.ID,
Position: 1,
}
playlistTrack2 := &models.PlaylistTrack{
PlaylistID: playlist.ID,
TrackID: track2.ID,
Position: 2,
}
require.NoError(t, db.Create(playlistTrack1).Error)
require.NoError(t, db.Create(playlistTrack2).Error)
// Create some track plays
play1 := &models.TrackPlay{
TrackID: track1.ID,
UserID: &user.ID,
Duration: 180,
}
play2 := &models.TrackPlay{
TrackID: track1.ID,
UserID: &user.ID,
Duration: 150,
}
play3 := &models.TrackPlay{
TrackID: track2.ID,
UserID: &user.ID,
Duration: 240,
}
require.NoError(t, db.Create(play1).Error)
require.NoError(t, db.Create(play2).Error)
require.NoError(t, db.Create(play3).Error)
// Create share link
shareLink := &models.PlaylistShareLink{
PlaylistID: playlist.ID,
UserID: user.ID,
ShareToken: "test-token-123",
AccessCount: 0,
}
require.NoError(t, db.Create(shareLink).Error)
// Create follow
follow := &models.PlaylistFollow{
PlaylistID: playlist.ID,
UserID: user.ID,
}
require.NoError(t, db.Create(follow).Error)
// Update follower count
playlist.FollowerCount = 1
require.NoError(t, db.Save(playlist).Error)
// Get stats
stats, err := service.GetPlaylistStats(ctx, playlist.ID)
require.NoError(t, err)
assert.NotNil(t, stats)
// Verify stats
assert.Equal(t, int64(3), stats.Plays) // 3 plays total (2 for track1, 1 for track2)
assert.Equal(t, int64(1), stats.Shares) // 1 share link
assert.Equal(t, int64(1), stats.Likes) // 1 follow
assert.Equal(t, int64(1), stats.Followers) // 1 follower
assert.Equal(t, 2, stats.TrackCount) // 2 tracks
}
func TestPlaylistAnalyticsService_GetPlaylistStats_NotFound(t *testing.T) {
service, _, cleanup := setupTestPlaylistAnalyticsService(t)
defer cleanup()
ctx := context.Background()
// Get stats for non-existent playlist
stats, err := service.GetPlaylistStats(ctx, uuid.New())
assert.Error(t, err)
assert.Nil(t, stats)
assert.Equal(t, "playlist not found", err.Error())
}
func TestPlaylistAnalyticsService_GetPlaylistStats_EmptyPlaylist(t *testing.T) {
service, db, cleanup := setupTestPlaylistAnalyticsService(t)
defer cleanup()
ctx := context.Background()
// Create test user
user := &models.User{
Username: "user1",
Email: "user1@example.com",
PasswordHash: "hash1",
Slug: "user1",
IsActive: true,
}
require.NoError(t, db.Create(user).Error)
// Create empty playlist
playlist := &models.Playlist{
UserID: user.ID,
Title: "Empty Playlist",
Description: "An empty playlist",
IsPublic: true,
TrackCount: 0,
FollowerCount: 0,
}
require.NoError(t, db.Create(playlist).Error)
// Get stats
stats, err := service.GetPlaylistStats(ctx, playlist.ID)
require.NoError(t, err)
assert.NotNil(t, stats)
// Verify stats for empty playlist
assert.Equal(t, int64(0), stats.Plays)
assert.Equal(t, int64(0), stats.Shares)
assert.Equal(t, int64(0), stats.Likes)
assert.Equal(t, int64(0), stats.Followers)
assert.Equal(t, 0, stats.TrackCount)
}
func TestPlaylistAnalyticsService_GetPlaylistStats_MultipleShares(t *testing.T) {
service, db, cleanup := setupTestPlaylistAnalyticsService(t)
defer cleanup()
ctx := context.Background()
// Create test user
user := &models.User{
Username: "user1",
Email: "user1@example.com",
PasswordHash: "hash1",
Slug: "user1",
IsActive: true,
}
require.NoError(t, db.Create(user).Error)
// Create test playlist
playlist := &models.Playlist{
UserID: user.ID,
Title: "Test Playlist",
Description: "A test playlist",
IsPublic: true,
TrackCount: 0,
FollowerCount: 0,
}
require.NoError(t, db.Create(playlist).Error)
// Create multiple share links
shareLink1 := &models.PlaylistShareLink{
PlaylistID: playlist.ID,
UserID: user.ID,
ShareToken: "token-1",
AccessCount: 0,
}
shareLink2 := &models.PlaylistShareLink{
PlaylistID: playlist.ID,
UserID: user.ID,
ShareToken: "token-2",
AccessCount: 0,
}
require.NoError(t, db.Create(shareLink1).Error)
require.NoError(t, db.Create(shareLink2).Error)
// Get stats
stats, err := service.GetPlaylistStats(ctx, playlist.ID)
require.NoError(t, err)
assert.NotNil(t, stats)
// Verify shares count
assert.Equal(t, int64(2), stats.Shares)
}
func TestPlaylistAnalyticsService_GetPlaylistStats_MultipleFollows(t *testing.T) {
service, db, cleanup := setupTestPlaylistAnalyticsService(t)
defer cleanup()
ctx := context.Background()
// Create test users
user1 := &models.User{
Username: "user1",
Email: "user1@example.com",
PasswordHash: "hash1",
Slug: "user1",
IsActive: true,
}
user2 := &models.User{
Username: "user2",
Email: "user2@example.com",
PasswordHash: "hash2",
Slug: "user2",
IsActive: true,
}
user3 := &models.User{
Username: "user3",
Email: "user3@example.com",
PasswordHash: "hash3",
Slug: "user3",
IsActive: true,
}
require.NoError(t, db.Create(user1).Error)
require.NoError(t, db.Create(user2).Error)
require.NoError(t, db.Create(user3).Error)
// Create test playlist
playlist := &models.Playlist{
UserID: user1.ID,
Title: "Test Playlist",
Description: "A test playlist",
IsPublic: true,
TrackCount: 0,
FollowerCount: 0,
}
require.NoError(t, db.Create(playlist).Error)
// Create multiple follows
follow1 := &models.PlaylistFollow{
PlaylistID: playlist.ID,
UserID: user2.ID,
}
follow2 := &models.PlaylistFollow{
PlaylistID: playlist.ID,
UserID: user3.ID,
}
require.NoError(t, db.Create(follow1).Error)
require.NoError(t, db.Create(follow2).Error)
// Update follower count
playlist.FollowerCount = 2
require.NoError(t, db.Save(playlist).Error)
// Get stats
stats, err := service.GetPlaylistStats(ctx, playlist.ID)
require.NoError(t, err)
assert.NotNil(t, stats)
// Verify follows count
assert.Equal(t, int64(2), stats.Likes)
assert.Equal(t, int64(2), stats.Followers)
}
func TestPlaylistAnalyticsService_IncrementPlaylistPlays(t *testing.T) {
service, _, cleanup := setupTestPlaylistAnalyticsService(t)
defer cleanup()
ctx := context.Background()
// Test increment (should not error, but doesn't do anything for now)
err := service.IncrementPlaylistPlays(ctx, uuid.New())
assert.NoError(t, err)
}