package models import ( "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/sqlite" "gorm.io/gorm" ) func setupTestBitrateAdaptationDB(t *testing.T) *gorm.DB { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err) // Enable foreign keys for SQLite db.Exec("PRAGMA foreign_keys = ON") sqlDB, _ := db.DB() sqlDB.SetMaxOpenConns(1) // Auto-migrate err = db.AutoMigrate(&User{}, &Track{}, &BitrateAdaptationLog{}) require.NoError(t, err) return db } func TestBitrateAdaptationLog_Create(t *testing.T) { db := setupTestBitrateAdaptationDB(t) userID := uuid.New() // Create test user user := &User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } err := db.Create(user).Error require.NoError(t, err) // Create test track track := &Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: TrackStatusCompleted, } err = db.Create(track).Error require.NoError(t, err) // Create bitrate adaptation log log := &BitrateAdaptationLog{ TrackID: track.ID, UserID: user.ID, OldBitrate: 128, NewBitrate: 192, Reason: BitrateReasonNetworkFast, NetworkBandwidth: intPtr(5000), // 5 Mbps } err = db.Create(log).Error require.NoError(t, err) assert.NotEqual(t, uuid.Nil, log.ID) assert.Equal(t, track.ID, log.TrackID) assert.Equal(t, user.ID, log.UserID) assert.Equal(t, 128, log.OldBitrate) assert.Equal(t, 192, log.NewBitrate) assert.Equal(t, BitrateReasonNetworkFast, log.Reason) assert.NotNil(t, log.NetworkBandwidth) assert.Equal(t, 5000, *log.NetworkBandwidth) assert.False(t, log.CreatedAt.IsZero()) } func TestBitrateAdaptationLog_DefaultValues(t *testing.T) { db := setupTestBitrateAdaptationDB(t) userID := uuid.New() // Create test user and track user := &User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } require.NoError(t, db.Create(user).Error) track := &Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: TrackStatusCompleted, } require.NoError(t, db.Create(track).Error) // Create log without network_bandwidth log := &BitrateAdaptationLog{ TrackID: track.ID, UserID: user.ID, OldBitrate: 192, NewBitrate: 128, Reason: BitrateReasonNetworkSlow, } err := db.Create(log).Error require.NoError(t, err) assert.Nil(t, log.NetworkBandwidth) assert.False(t, log.CreatedAt.IsZero()) } func TestBitrateAdaptationLog_Relations(t *testing.T) { db := setupTestBitrateAdaptationDB(t) userID := uuid.New() // Create test user user := &User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } err := db.Create(user).Error require.NoError(t, err) // Create test track track := &Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: TrackStatusCompleted, } err = db.Create(track).Error require.NoError(t, err) // Create bitrate adaptation log log := &BitrateAdaptationLog{ TrackID: track.ID, UserID: user.ID, OldBitrate: 128, NewBitrate: 192, Reason: BitrateReasonUserSelected, } err = db.Create(log).Error require.NoError(t, err) // Test relation with Track var loadedLog BitrateAdaptationLog err = db.Preload("Track").First(&loadedLog, log.ID).Error require.NoError(t, err) assert.Equal(t, track.ID, loadedLog.Track.ID) assert.Equal(t, track.Title, loadedLog.Track.Title) // Test relation with User err = db.Preload("User").First(&loadedLog, log.ID).Error require.NoError(t, err) assert.Equal(t, user.ID, loadedLog.User.ID) assert.Equal(t, user.Username, loadedLog.User.Username) } func TestBitrateAdaptationLog_CascadeDelete(t *testing.T) { db := setupTestBitrateAdaptationDB(t) userID := uuid.New() // Create test user user := &User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } err := db.Create(user).Error require.NoError(t, err) // Create test track track := &Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: TrackStatusCompleted, } err = db.Create(track).Error require.NoError(t, err) // Create bitrate adaptation log log := &BitrateAdaptationLog{ TrackID: track.ID, UserID: user.ID, OldBitrate: 128, NewBitrate: 192, Reason: BitrateReasonNetworkFast, } err = db.Create(log).Error require.NoError(t, err) // Delete track - should cascade delete the log err = db.Unscoped().Delete(track).Error require.NoError(t, err) // Verify log is deleted var count int64 db.Model(&BitrateAdaptationLog{}).Where("id = ?", log.ID).Count(&count) assert.Equal(t, int64(0), count, "Log should be deleted when track is deleted") } func TestBitrateAdaptationLog_ReasonValues(t *testing.T) { db := setupTestBitrateAdaptationDB(t) userID := uuid.New() // Create test user and track user := &User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } require.NoError(t, db.Create(user).Error) track := &Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: TrackStatusCompleted, } require.NoError(t, db.Create(track).Error) // Test all reason values reasons := []BitrateAdaptationReason{ BitrateReasonNetworkSlow, BitrateReasonNetworkFast, BitrateReasonUserSelected, BitrateReasonBufferLow, } for _, reason := range reasons { log := &BitrateAdaptationLog{ TrackID: track.ID, UserID: user.ID, OldBitrate: 128, NewBitrate: 192, Reason: reason, } err := db.Create(log).Error require.NoError(t, err, "Failed to create log with reason: %s", reason) assert.Equal(t, reason, log.Reason) } } func TestBitrateAdaptationLog_Indexes(t *testing.T) { db := setupTestBitrateAdaptationDB(t) userID := uuid.New() // Create test user and track user := &User{ ID: userID, Username: "testuser", Email: "test@example.com", IsActive: true, } require.NoError(t, db.Create(user).Error) track := &Track{ UserID: userID, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: TrackStatusCompleted, } require.NoError(t, db.Create(track).Error) // Create multiple logs for i := 0; i < 5; i++ { log := &BitrateAdaptationLog{ TrackID: track.ID, UserID: user.ID, OldBitrate: 128 + i*32, NewBitrate: 192 + i*32, Reason: BitrateReasonNetworkFast, } require.NoError(t, db.Create(log).Error) } // Test query by track_id (should use index) var logsByTrack []BitrateAdaptationLog err := db.Where("track_id = ?", track.ID).Find(&logsByTrack).Error require.NoError(t, err) assert.Equal(t, 5, len(logsByTrack)) // Test query by user_id (should use index) var logsByUser []BitrateAdaptationLog err = db.Where("user_id = ?", user.ID).Find(&logsByUser).Error require.NoError(t, err) assert.Equal(t, 5, len(logsByUser)) // Test query by created_at (should use index) var logsByDate []BitrateAdaptationLog now := time.Now() err = db.Where("created_at >= ?", now.Add(-1*time.Hour)).Find(&logsByDate).Error require.NoError(t, err) assert.GreaterOrEqual(t, len(logsByDate), 5) } func TestBitrateAdaptationLog_TableName(t *testing.T) { log := BitrateAdaptationLog{} assert.Equal(t, "bitrate_adaptation_logs", log.TableName()) } // Helper function func intPtr(i int) *int { return &i }