498 lines
15 KiB
Go
498 lines
15 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"veza-backend-api/internal/models"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap/zaptest"
|
|
)
|
|
|
|
func setupTestHLSDir(t *testing.T) (string, func()) {
|
|
testDir := filepath.Join(os.TempDir(), fmt.Sprintf("hls_test_%d", time.Now().UnixNano()))
|
|
err := os.MkdirAll(testDir, 0755)
|
|
require.NoError(t, err)
|
|
|
|
cleanup := func() {
|
|
os.RemoveAll(testDir)
|
|
}
|
|
|
|
return testDir, cleanup
|
|
}
|
|
|
|
func createTestTrack(t *testing.T, filePath string) *models.Track {
|
|
// Créer un fichier audio de test minimal
|
|
err := os.WriteFile(filePath, []byte("fake audio content"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
// GO-004: Utiliser UUID au lieu de int
|
|
trackID := uuid.New()
|
|
userID := uuid.New()
|
|
return &models.Track{
|
|
ID: trackID,
|
|
UserID: userID,
|
|
Title: "Test Track",
|
|
FilePath: filePath,
|
|
FileSize: 1024,
|
|
Format: "mp3",
|
|
Duration: 180,
|
|
Status: models.TrackStatusCompleted,
|
|
}
|
|
}
|
|
|
|
func TestNewHLSTranscodeService(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
service := NewHLSTranscodeService("/tmp/hls", logger)
|
|
|
|
assert.NotNil(t, service)
|
|
assert.Equal(t, "/tmp/hls", service.outputDir)
|
|
assert.Equal(t, []int{128, 192, 320}, service.bitrates)
|
|
assert.NotNil(t, service.logger)
|
|
}
|
|
|
|
func TestNewHLSTranscodeService_NilLogger(t *testing.T) {
|
|
service := NewHLSTranscodeService("/tmp/hls", nil)
|
|
|
|
assert.NotNil(t, service)
|
|
assert.NotNil(t, service.logger) // Devrait créer un logger Nop
|
|
}
|
|
|
|
func TestHLSTranscodeService_SetBitrates(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
service := NewHLSTranscodeService("/tmp/hls", logger)
|
|
|
|
customBitrates := []int{64, 128, 256}
|
|
service.SetBitrates(customBitrates)
|
|
|
|
assert.Equal(t, customBitrates, service.bitrates)
|
|
}
|
|
|
|
func TestHLSTranscodeService_TranscodeTrack_NilTrack(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
service := NewHLSTranscodeService("/tmp/hls", logger)
|
|
|
|
ctx := context.Background()
|
|
result, err := service.TranscodeTrack(ctx, nil)
|
|
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Contains(t, err.Error(), "track cannot be nil")
|
|
}
|
|
|
|
func TestHLSTranscodeService_TranscodeTrack_EmptyFilePath(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
service := NewHLSTranscodeService("/tmp/hls", logger)
|
|
|
|
// GO-004: Utiliser UUID au lieu de int
|
|
trackID := uuid.New()
|
|
track := &models.Track{
|
|
ID: trackID,
|
|
FilePath: "",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
result, err := service.TranscodeTrack(ctx, track)
|
|
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Contains(t, err.Error(), "file path is empty")
|
|
}
|
|
|
|
func TestHLSTranscodeService_TranscodeTrack_FileNotExists(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// GO-004: Utiliser UUID au lieu de int
|
|
trackID := uuid.New()
|
|
track := &models.Track{
|
|
ID: trackID,
|
|
FilePath: "/nonexistent/file.mp3",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
result, err := service.TranscodeTrack(ctx, track)
|
|
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Contains(t, err.Error(), "file does not exist")
|
|
}
|
|
|
|
func TestHLSTranscodeService_TranscodeTrack_CreatesDirectory(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer un fichier audio de test
|
|
testAudioFile := filepath.Join(testDir, "test.mp3")
|
|
track := createTestTrack(t, testAudioFile)
|
|
|
|
ctx := context.Background()
|
|
|
|
// Note: Ce test échouera si ffmpeg n'est pas installé
|
|
// C'est acceptable car c'est un test d'intégration
|
|
result, err := service.TranscodeTrack(ctx, track)
|
|
|
|
// Si ffmpeg n'est pas disponible, on s'attend à une erreur
|
|
if err != nil {
|
|
// Vérifier que le répertoire a été créé même en cas d'erreur
|
|
trackDir := filepath.Join(testDir, fmt.Sprintf("track_%d", track.ID))
|
|
// Le répertoire peut ne pas exister si l'erreur survient avant sa création
|
|
// ou peut exister si l'erreur survient après
|
|
_ = trackDir
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
} else {
|
|
// Si ffmpeg est disponible, vérifier que tout a été créé
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, track.ID, result.TrackID)
|
|
assert.Contains(t, result.PlaylistURL, "master.m3u8")
|
|
assert.Greater(t, result.SegmentsCount, 0)
|
|
assert.Equal(t, models.HLSStatusReady, result.Status)
|
|
}
|
|
}
|
|
|
|
func TestHLSTranscodeService_CountSegments(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer une structure de test
|
|
trackDir := filepath.Join(testDir, "track_123")
|
|
qualityDir1 := filepath.Join(trackDir, "128k")
|
|
qualityDir2 := filepath.Join(trackDir, "192k")
|
|
|
|
require.NoError(t, os.MkdirAll(qualityDir1, 0755))
|
|
require.NoError(t, os.MkdirAll(qualityDir2, 0755))
|
|
|
|
// Créer des segments de test
|
|
for i := 0; i < 3; i++ {
|
|
segmentPath := filepath.Join(qualityDir1, fmt.Sprintf("segment_%03d.ts", i))
|
|
require.NoError(t, os.WriteFile(segmentPath, []byte("test"), 0644))
|
|
}
|
|
|
|
for i := 0; i < 2; i++ {
|
|
segmentPath := filepath.Join(qualityDir2, fmt.Sprintf("segment_%03d.ts", i))
|
|
require.NoError(t, os.WriteFile(segmentPath, []byte("test"), 0644))
|
|
}
|
|
|
|
count, err := service.countSegments(trackDir)
|
|
|
|
assert.NoError(t, err)
|
|
// Devrait retourner le maximum (3 segments dans 128k)
|
|
assert.Equal(t, 3, count)
|
|
}
|
|
|
|
func TestHLSTranscodeService_CountSegments_EmptyDir(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
trackDir := filepath.Join(testDir, "track_123")
|
|
require.NoError(t, os.MkdirAll(trackDir, 0755))
|
|
|
|
// Créer les répertoires de qualité vides
|
|
for _, bitrate := range service.bitrates {
|
|
qualityDir := filepath.Join(trackDir, fmt.Sprintf("%dk", bitrate))
|
|
require.NoError(t, os.MkdirAll(qualityDir, 0755))
|
|
}
|
|
|
|
count, err := service.countSegments(trackDir)
|
|
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 0, count)
|
|
}
|
|
|
|
func TestHLSTranscodeService_CountSegments_NonexistentDir(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
count, err := service.countSegments("/nonexistent/dir")
|
|
|
|
assert.Error(t, err)
|
|
assert.Equal(t, 0, count)
|
|
}
|
|
|
|
func TestHLSTranscodeService_CountSegments_MultipleBitrates(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer un répertoire de track avec des segments
|
|
trackDir := filepath.Join(testDir, "track_123")
|
|
require.NoError(t, os.MkdirAll(trackDir, 0755))
|
|
|
|
// Créer des répertoires de qualité avec différents nombres de segments
|
|
qualityDir128 := filepath.Join(trackDir, "128k")
|
|
require.NoError(t, os.MkdirAll(qualityDir128, 0755))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir128, "segment_000.ts"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir128, "segment_001.ts"), []byte("data"), 0644))
|
|
|
|
qualityDir192 := filepath.Join(trackDir, "192k")
|
|
require.NoError(t, os.MkdirAll(qualityDir192, 0755))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir192, "segment_000.ts"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir192, "segment_001.ts"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir192, "segment_002.ts"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir192, "segment_003.ts"), []byte("data"), 0644))
|
|
|
|
qualityDir320 := filepath.Join(trackDir, "320k")
|
|
require.NoError(t, os.MkdirAll(qualityDir320, 0755))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir320, "segment_000.ts"), []byte("data"), 0644))
|
|
|
|
count, err := service.countSegments(trackDir)
|
|
|
|
assert.NoError(t, err)
|
|
// Devrait retourner le maximum (4 segments dans 192k)
|
|
assert.Equal(t, 4, count)
|
|
}
|
|
|
|
func TestHLSTranscodeService_CountSegments_OnlySegmentFiles(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer un répertoire de track avec des segments
|
|
trackDir := filepath.Join(testDir, "track_123")
|
|
require.NoError(t, os.MkdirAll(trackDir, 0755))
|
|
|
|
qualityDir := filepath.Join(trackDir, "128k")
|
|
require.NoError(t, os.MkdirAll(qualityDir, 0755))
|
|
// Créer des fichiers segment_*.ts
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir, "segment_000.ts"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir, "segment_001.ts"), []byte("data"), 0644))
|
|
// Créer d'autres fichiers qui ne doivent pas être comptés
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir, "playlist.m3u8"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir, "other.ts"), []byte("data"), 0644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(qualityDir, "segment_other.txt"), []byte("data"), 0644))
|
|
|
|
count, err := service.countSegments(trackDir)
|
|
|
|
assert.NoError(t, err)
|
|
// Devrait compter uniquement les fichiers segment_*.ts (2 fichiers)
|
|
assert.Equal(t, 2, count)
|
|
}
|
|
|
|
func TestHLSTranscodeService_GetPlaylistDuration(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer une playlist de test
|
|
playlistContent := `#EXTM3U
|
|
#EXT-X-VERSION:3
|
|
#EXTINF:10.0,
|
|
segment_000.ts
|
|
#EXTINF:10.5,
|
|
segment_001.ts
|
|
#EXTINF:9.5,
|
|
segment_002.ts
|
|
#EXT-X-ENDLIST
|
|
`
|
|
|
|
playlistPath := filepath.Join(testDir, "playlist.m3u8")
|
|
require.NoError(t, os.WriteFile(playlistPath, []byte(playlistContent), 0644))
|
|
|
|
duration := service.getPlaylistDuration(playlistPath)
|
|
|
|
assert.Equal(t, 30.0, duration)
|
|
}
|
|
|
|
func TestHLSTranscodeService_GetPlaylistDuration_NonexistentFile(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
duration := service.getPlaylistDuration("/nonexistent/playlist.m3u8")
|
|
|
|
assert.Equal(t, 0.0, duration)
|
|
}
|
|
|
|
func TestHLSTranscodeService_GenerateMasterPlaylist(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer les répertoires et playlists de qualité
|
|
bitrates := []int{128, 192, 320}
|
|
for _, bitrate := range bitrates {
|
|
qualityDir := filepath.Join(testDir, fmt.Sprintf("%dk", bitrate))
|
|
require.NoError(t, os.MkdirAll(qualityDir, 0755))
|
|
playlistPath := filepath.Join(qualityDir, "playlist.m3u8")
|
|
require.NoError(t, os.WriteFile(playlistPath, []byte("#EXTM3U\n"), 0644))
|
|
}
|
|
|
|
err := service.generateMasterPlaylist(testDir, bitrates)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que le fichier master.m3u8 a été créé
|
|
masterPlaylistPath := filepath.Join(testDir, "master.m3u8")
|
|
assert.FileExists(t, masterPlaylistPath)
|
|
|
|
// Vérifier le contenu
|
|
content, err := os.ReadFile(masterPlaylistPath)
|
|
require.NoError(t, err)
|
|
|
|
contentStr := string(content)
|
|
assert.Contains(t, contentStr, "#EXTM3U")
|
|
assert.Contains(t, contentStr, "#EXT-X-VERSION:3")
|
|
assert.Contains(t, contentStr, "128k/playlist.m3u8")
|
|
assert.Contains(t, contentStr, "192k/playlist.m3u8")
|
|
assert.Contains(t, contentStr, "320k/playlist.m3u8")
|
|
}
|
|
|
|
func TestHLSTranscodeService_CleanupTrackDir(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer un répertoire de track
|
|
// GO-004: Utiliser UUID au lieu de int
|
|
// Note: CleanupTrackDir uses format "track_<trackID>", so we need to match that
|
|
trackID := uuid.New()
|
|
trackDir := filepath.Join(testDir, fmt.Sprintf("track_%s", trackID.String()))
|
|
require.NoError(t, os.MkdirAll(trackDir, 0755))
|
|
require.NoError(t, os.WriteFile(filepath.Join(trackDir, "test.txt"), []byte("test"), 0644))
|
|
|
|
// Nettoyer
|
|
err := service.CleanupTrackDir(trackID)
|
|
|
|
assert.NoError(t, err)
|
|
assert.NoDirExists(t, trackDir)
|
|
}
|
|
|
|
func TestHLSTranscodeService_CleanupTrackDir_Nonexistent(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Nettoyer un répertoire qui n'existe pas (ne devrait pas retourner d'erreur)
|
|
// GO-004: Utiliser UUID au lieu de int
|
|
nonexistentTrackID := uuid.New()
|
|
err := service.CleanupTrackDir(nonexistentTrackID)
|
|
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestHLSTranscodeService_TranscodeTrack_WithCustomBitrates(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
service.SetBitrates([]int{64, 128})
|
|
|
|
testAudioFile := filepath.Join(testDir, "test.mp3")
|
|
track := createTestTrack(t, testAudioFile)
|
|
|
|
ctx := context.Background()
|
|
result, err := service.TranscodeTrack(ctx, track)
|
|
|
|
// Si ffmpeg n'est pas disponible, on s'attend à une erreur
|
|
if err != nil {
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Len(t, result.Bitrates, 2)
|
|
assert.Contains(t, result.Bitrates, 64)
|
|
assert.Contains(t, result.Bitrates, 128)
|
|
}
|
|
}
|
|
|
|
func TestHLSTranscodeService_GetPlaylistDuration_InvalidFormat(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
// Créer une playlist avec format invalide
|
|
playlistContent := `#EXTM3U
|
|
#EXTINF:invalid,
|
|
segment_000.ts
|
|
`
|
|
|
|
playlistPath := filepath.Join(testDir, "playlist.m3u8")
|
|
require.NoError(t, os.WriteFile(playlistPath, []byte(playlistContent), 0644))
|
|
|
|
duration := service.getPlaylistDuration(playlistPath)
|
|
|
|
// Devrait retourner 0 pour format invalide
|
|
assert.Equal(t, 0.0, duration)
|
|
}
|
|
|
|
func TestHLSTranscodeService_GetPlaylistDuration_EmptyFile(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
playlistPath := filepath.Join(testDir, "empty.m3u8")
|
|
require.NoError(t, os.WriteFile(playlistPath, []byte(""), 0644))
|
|
|
|
duration := service.getPlaylistDuration(playlistPath)
|
|
|
|
assert.Equal(t, 0.0, duration)
|
|
}
|
|
|
|
func TestHLSTranscodeService_GenerateMasterPlaylist_EmptyBitrates(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
testDir, cleanup := setupTestHLSDir(t)
|
|
defer cleanup()
|
|
|
|
service := NewHLSTranscodeService(testDir, logger)
|
|
|
|
err := service.generateMasterPlaylist(testDir, []int{})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que le fichier master.m3u8 a été créé
|
|
masterPlaylistPath := filepath.Join(testDir, "master.m3u8")
|
|
assert.FileExists(t, masterPlaylistPath)
|
|
|
|
// Vérifier le contenu (devrait contenir seulement le header)
|
|
content, err := os.ReadFile(masterPlaylistPath)
|
|
require.NoError(t, err)
|
|
|
|
contentStr := string(content)
|
|
assert.Contains(t, contentStr, "#EXTM3U")
|
|
assert.Contains(t, contentStr, "#EXT-X-VERSION:3")
|
|
}
|