391 lines
13 KiB
Go
391 lines
13 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap/zaptest"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
|
|
"veza-backend-api/internal/models"
|
|
)
|
|
|
|
func setupTestBitrateAdaptationServiceDB(t *testing.T) (*gorm.DB, uuid.UUID, uuid.UUID) {
|
|
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.BitrateAdaptationLog{})
|
|
require.NoError(t, err)
|
|
|
|
userID := uuid.New()
|
|
// Create test user
|
|
user := &models.User{
|
|
ID: userID,
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
IsActive: true,
|
|
}
|
|
err = db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
// Create test track
|
|
trackID := uuid.New()
|
|
track := &models.Track{
|
|
ID: trackID,
|
|
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)
|
|
|
|
return db, userID, trackID
|
|
}
|
|
|
|
func TestNewBitrateAdaptationService(t *testing.T) {
|
|
db, _, _ := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
|
|
assert.NotNil(t, service)
|
|
assert.Equal(t, db, service.db)
|
|
assert.Equal(t, bandwidthService, service.bandwidthService)
|
|
assert.NotNil(t, service.logger)
|
|
}
|
|
|
|
func TestNewBitrateAdaptationService_NilLogger(t *testing.T) {
|
|
db, _, _ := setupTestBitrateAdaptationServiceDB(t)
|
|
bandwidthService := NewBandwidthDetectionService(nil)
|
|
|
|
service := NewBitrateAdaptationService(db, bandwidthService, nil)
|
|
|
|
assert.NotNil(t, service)
|
|
assert.NotNil(t, service.logger)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_NoChange(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec bitrate qui ne change pas
|
|
// Bande passante de 2 Mbps = 2097152 bps, avec buffer 20% = 1677 kbps disponible
|
|
// Recommandation: 320 kbps
|
|
// Current: 320 kbps, donc pas de changement
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 320, 2097152, 0.5)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, newBitrate)
|
|
|
|
// Vérifier qu'aucun log n'a été créé
|
|
var count int64
|
|
db.Model(&models.BitrateAdaptationLog{}).Count(&count)
|
|
assert.Equal(t, int64(0), count)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_Increase(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec augmentation de bitrate
|
|
// Bande passante de 10 Mbps = 10485760 bps, avec buffer 20% = 8388 kbps disponible
|
|
// Recommandation: 320 kbps
|
|
// Current: 128 kbps, buffer: 0.5 (50%)
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 128, 10485760, 0.5)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, newBitrate)
|
|
|
|
// Vérifier qu'un log a été créé
|
|
var log models.BitrateAdaptationLog
|
|
err = db.First(&log).Error
|
|
require.NoError(t, err)
|
|
assert.Equal(t, trackID, log.TrackID)
|
|
assert.Equal(t, userID, log.UserID)
|
|
assert.Equal(t, 128, log.OldBitrate)
|
|
assert.Equal(t, 320, log.NewBitrate)
|
|
assert.Equal(t, models.BitrateReasonNetworkFast, log.Reason)
|
|
assert.NotNil(t, log.NetworkBandwidth)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_Decrease(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec diminution de bitrate
|
|
// Bande passante de 300 kbps = 307200 bps, avec buffer 20% = 245 kbps disponible
|
|
// Recommandation: 192 kbps
|
|
// Current: 320 kbps, buffer: 0.5 (50%)
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 320, 307200, 0.5)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 192, newBitrate)
|
|
|
|
// Vérifier qu'un log a été créé
|
|
var log models.BitrateAdaptationLog
|
|
err = db.First(&log).Error
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, log.OldBitrate)
|
|
assert.Equal(t, 192, log.NewBitrate)
|
|
assert.Equal(t, models.BitrateReasonNetworkSlow, log.Reason)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_LowBuffer_PreventIncrease(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec buffer faible qui empêche l'augmentation
|
|
// Bande passante de 10 Mbps = 10485760 bps, recommandation: 320 kbps
|
|
// Current: 128 kbps, buffer: 0.15 (15% < 20%)
|
|
// L'augmentation devrait être bloquée
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 128, 10485760, 0.15)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 128, newBitrate) // Pas d'augmentation
|
|
|
|
// Vérifier qu'aucun log n'a été créé (pas de changement)
|
|
var count int64
|
|
db.Model(&models.BitrateAdaptationLog{}).Count(&count)
|
|
assert.Equal(t, int64(0), count)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_VeryLowBuffer_ForceDecrease(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec buffer très faible qui force la diminution
|
|
// Bande passante de 10 Mbps = 10485760 bps, recommandation: 320 kbps
|
|
// Current: 320 kbps, buffer: 0.05 (5% < 10%)
|
|
// La diminution devrait être forcée
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 320, 10485760, 0.05)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 192, newBitrate) // Diminution forcée
|
|
|
|
// Vérifier qu'un log a été créé
|
|
var log models.BitrateAdaptationLog
|
|
err = db.First(&log).Error
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, log.OldBitrate)
|
|
assert.Equal(t, 192, log.NewBitrate)
|
|
assert.Equal(t, models.BitrateReasonBufferLow, log.Reason)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_VeryLowBuffer_192to128(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec buffer très faible, passage de 192 à 128
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 192, 10485760, 0.05)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 128, newBitrate)
|
|
|
|
// Vérifier qu'un log a été créé
|
|
var log models.BitrateAdaptationLog
|
|
err = db.First(&log).Error
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 192, log.OldBitrate)
|
|
assert.Equal(t, 128, log.NewBitrate)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_InvalidParameters(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec trackID invalide
|
|
_, err := service.AdaptBitrate(ctx, uuid.Nil, userID, 128, 10485760, 0.5)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid track ID")
|
|
|
|
// Test avec userID invalide
|
|
_, err = service.AdaptBitrate(ctx, trackID, uuid.Nil, 128, 10485760, 0.5)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid user ID")
|
|
|
|
// Test avec currentBitrate invalide
|
|
_, err = service.AdaptBitrate(ctx, trackID, userID, 0, 10485760, 0.5)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid current bitrate")
|
|
|
|
// Test avec bufferLevel invalide (négatif)
|
|
_, err = service.AdaptBitrate(ctx, trackID, userID, 128, 10485760, -0.1)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid buffer level")
|
|
|
|
// Test avec bufferLevel invalide (> 1.0)
|
|
_, err = service.AdaptBitrate(ctx, trackID, userID, 128, 10485760, 1.5)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid buffer level")
|
|
}
|
|
|
|
func TestBitrateAdaptationService_DetermineReason(t *testing.T) {
|
|
db, _, _ := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
|
|
// Test avec buffer faible
|
|
reason := service.determineReason(128, 320, 0.15)
|
|
assert.Equal(t, models.BitrateReasonBufferLow, reason)
|
|
|
|
// Test avec augmentation (buffer normal)
|
|
reason = service.determineReason(128, 320, 0.5)
|
|
assert.Equal(t, models.BitrateReasonNetworkFast, reason)
|
|
|
|
// Test avec diminution (buffer normal)
|
|
reason = service.determineReason(320, 192, 0.5)
|
|
assert.Equal(t, models.BitrateReasonNetworkSlow, reason)
|
|
|
|
// Test avec buffer faible mais augmentation
|
|
reason = service.determineReason(128, 192, 0.15)
|
|
assert.Equal(t, models.BitrateReasonBufferLow, reason)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_MultipleAdaptations(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Première adaptation: 128 -> 192
|
|
// Bande passante de 300 kbps = 307200 bps, avec buffer 20% = 245 kbps disponible
|
|
// Recommandation: 192 kbps
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 128, 307200, 0.5)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 192, newBitrate)
|
|
|
|
// Deuxième adaptation: 192 -> 320
|
|
// Bande passante de 10 Mbps = 10485760 bps, avec buffer 20% = 8388 kbps disponible
|
|
// Recommandation: 320 kbps
|
|
newBitrate, err = service.AdaptBitrate(ctx, trackID, userID, 192, 10485760, 0.5)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, newBitrate)
|
|
|
|
// Vérifier qu'il y a 2 logs
|
|
var count int64
|
|
db.Model(&models.BitrateAdaptationLog{}).Count(&count)
|
|
assert.Equal(t, int64(2), count)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_EdgeCases(t *testing.T) {
|
|
db, userID, trackID := setupTestBitrateAdaptationServiceDB(t)
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// Test avec buffer exactement à 20%
|
|
newBitrate, err := service.AdaptBitrate(ctx, trackID, userID, 128, 10485760, 0.2)
|
|
require.NoError(t, err)
|
|
// À 20%, l'augmentation devrait être permise
|
|
assert.Equal(t, 320, newBitrate)
|
|
|
|
// Nettoyer les logs précédents
|
|
db.Exec("DELETE FROM bitrate_adaptation_logs")
|
|
|
|
// Test avec buffer exactement à 10%
|
|
newBitrate, err = service.AdaptBitrate(ctx, trackID, userID, 320, 10485760, 0.1)
|
|
require.NoError(t, err)
|
|
// À 10%, la diminution devrait être forcée
|
|
assert.Equal(t, 192, newBitrate)
|
|
|
|
// Nettoyer les logs précédents
|
|
db.Exec("DELETE FROM bitrate_adaptation_logs")
|
|
|
|
// Test avec buffer à 0%
|
|
newBitrate, err = service.AdaptBitrate(ctx, trackID, userID, 320, 10485760, 0.0)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 192, newBitrate)
|
|
|
|
// Nettoyer les logs précédents
|
|
db.Exec("DELETE FROM bitrate_adaptation_logs")
|
|
|
|
// Test avec buffer à 100%
|
|
newBitrate, err = service.AdaptBitrate(ctx, trackID, userID, 128, 10485760, 1.0)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, newBitrate)
|
|
}
|
|
|
|
func TestBitrateAdaptationService_AdaptBitrate_LogCreationFailure(t *testing.T) {
|
|
// Créer une DB qui va échouer lors de la création
|
|
// On utilise une table qui n'existe pas pour simuler l'erreur
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
|
|
// Ne pas créer la table bitrate_adaptation_logs pour simuler une erreur
|
|
// Mais on doit créer User et Track pour que les foreign keys fonctionnent
|
|
err = db.AutoMigrate(&models.User{}, &models.Track{})
|
|
require.NoError(t, err)
|
|
|
|
userID := uuid.New()
|
|
// Create test user
|
|
user := &models.User{
|
|
ID: userID,
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
IsActive: true,
|
|
}
|
|
require.NoError(t, db.Create(user).Error)
|
|
|
|
// 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,
|
|
}
|
|
require.NoError(t, db.Create(track).Error)
|
|
|
|
logger := zaptest.NewLogger(t)
|
|
bandwidthService := NewBandwidthDetectionService(logger)
|
|
service := NewBitrateAdaptationService(db, bandwidthService, logger)
|
|
ctx := context.Background()
|
|
|
|
// L'adaptation devrait quand même fonctionner même si le log échoue
|
|
newBitrate, err := service.AdaptBitrate(ctx, track.ID, userID, 128, 10485760, 0.5)
|
|
|
|
// L'adaptation ne devrait pas retourner d'erreur même si le log échoue
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 320, newBitrate)
|
|
}
|