package handlers import ( "bytes" "encoding/json" "fmt" "github.com/google/uuid" "mime/multipart" "net/http" "net/http/httptest" "os" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "go.uber.org/zap" "gorm.io/driver/sqlite" "gorm.io/gorm" "veza-backend-api/internal/models" "veza-backend-api/internal/services" ) // createTestMP3 creates a minimal valid MP3 file header for testing func createTestMP3() ([]byte, error) { // MP3 file header (ID3v2 tag) header := []byte{ 'I', 'D', '3', // ID3v2 marker 0x03, 0x00, // Version 0x00, // Flags 0x00, 0x00, 0x00, 0x00, // Size (0 for test) } return header, nil } // createTestAudioFile creates a test audio file with specified extension func createTestAudioFile(ext string) ([]byte, error) { switch ext { case ".mp3": return createTestMP3() case ".flac": // FLAC file header return []byte{'f', 'L', 'a', 'C', 0x00, 0x00, 0x00, 0x22}, nil case ".wav": // WAV file header return []byte{'R', 'I', 'F', 'F', 0x00, 0x00, 0x00, 0x00, 'W', 'A', 'V', 'E'}, nil case ".ogg": // OGG file header return []byte{'O', 'g', 'g', 'S', 0x00, 0x02, 0x00, 0x00}, nil default: return createTestMP3() } } func setupTestTrackHandler(t *testing.T) (*TrackHandler, *gorm.DB, func()) { gin.SetMode(gin.TestMode) // Setup in-memory SQLite database db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) assert.NoError(t, err) // Auto-migrate err = db.AutoMigrate(&models.Track{}, &models.User{}) assert.NoError(t, err) // Create test user user := &models.User{ ID: 123, Username: "testuser", Email: "test@example.com", IsActive: true, } err = db.Create(user).Error assert.NoError(t, err) // Setup logger logger := zap.NewNop() // Setup test upload directory testUploadDir := "test_uploads/tracks" trackService := services.NewTrackService(db, logger, testUploadDir) trackUploadService := services.NewTrackUploadService(db, logger) chunkService := services.NewTrackChunkService("test_uploads/tracks/chunks", logger) trackLikeService := services.NewTrackLikeService(db, logger) // Pass nil for streamService in tests trackHandler := NewTrackHandler(trackService, trackUploadService, chunkService, trackLikeService, nil) // Cleanup function cleanup := func() { os.RemoveAll("test_uploads") } return trackHandler, db, cleanup } func TestTrackHandler_UploadTrack_Success(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Create test MP3 file mp3Data, err := createTestAudioFile(".mp3") assert.NoError(t, err) // Create multipart form body := new(bytes.Buffer) writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("file", "test.mp3") assert.NoError(t, err) _, err = part.Write(mp3Data) assert.NoError(t, err) writer.Close() // Create request req := httptest.NewRequest("POST", "/api/v1/tracks", body) req.Header.Set("Content-Type", writer.FormDataContentType()) // Set user_id in context (simulating auth middleware) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) // Execute handler.UploadTrack(c) // Assert assert.Equal(t, http.StatusCreated, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "track") track := response["track"].(map[string]interface{}) assert.Equal(t, float64(123), track["user_id"]) assert.Equal(t, "test", track["title"]) assert.Equal(t, "MP3", track["format"]) // Verify track was created in DB var dbTrack models.Track err = db.First(&dbTrack, track["id"]).Error assert.NoError(t, err) assert.Equal(t, int64(123), dbTrack.UserID) assert.Equal(t, "test", dbTrack.Title) } func TestTrackHandler_UploadTrack_Unauthorized(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Create request without user_id in context req := httptest.NewRequest("POST", "/api/v1/tracks/upload", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req // No user_id set // Execute handler.UploadTrack(c) // Assert assert.Equal(t, http.StatusUnauthorized, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "unauthorized", response["error"]) } func TestTrackHandler_UploadTrack_NoFile(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Create request without file req := httptest.NewRequest("POST", "/api/v1/tracks/upload", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) // Execute handler.UploadTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response["error"], "no file provided") } func TestTrackHandler_UploadTrack_InvalidFormat(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Create test file with invalid format invalidData := []byte("not an audio file") // Create multipart form body := new(bytes.Buffer) writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("file", "test.txt") assert.NoError(t, err) _, err = part.Write(invalidData) assert.NoError(t, err) writer.Close() // Create request req := httptest.NewRequest("POST", "/api/v1/tracks", body) req.Header.Set("Content-Type", writer.FormDataContentType()) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) // Execute handler.UploadTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response["error"], "Invalid file format") } func TestTrackHandler_UploadTrack_FileTooLarge(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Create a large file (over 100MB) largeData := make([]byte, 101*1024*1024) // 101MB // Create multipart form body := new(bytes.Buffer) writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("file", "large.mp3") assert.NoError(t, err) _, err = part.Write(largeData) assert.NoError(t, err) writer.Close() // Create request req := httptest.NewRequest("POST", "/api/v1/tracks", body) req.Header.Set("Content-Type", writer.FormDataContentType()) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) // Execute handler.UploadTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response["error"], "File size exceeds maximum") } func TestTrackHandler_UploadTrack_ValidFormats(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() formats := []struct { ext string expected string }{ {".mp3", "MP3"}, {".flac", "FLAC"}, {".wav", "WAV"}, {".ogg", "OGG"}, } for _, format := range formats { t.Run(format.ext, func(t *testing.T) { // Create test audio file audioData, err := createTestAudioFile(format.ext) assert.NoError(t, err) // Create multipart form body := new(bytes.Buffer) writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("file", "test"+format.ext) assert.NoError(t, err) _, err = part.Write(audioData) assert.NoError(t, err) writer.Close() // Create request req := httptest.NewRequest("POST", "/api/v1/tracks", body) req.Header.Set("Content-Type", writer.FormDataContentType()) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) // Execute handler.UploadTrack(c) // Assert if w.Code != http.StatusCreated { t.Logf("Response body: %s", w.Body.String()) } assert.Equal(t, http.StatusCreated, w.Code, "Format %s should be accepted", format.ext) }) } } func TestTrackHandler_ListTracks_Success(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer quelques tracks avec statut completed track1 := &models.Track{ UserID: 123, Title: "Track 1", FilePath: "/test/track1.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Genre: "Rock", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track1).Error assert.NoError(t, err) track2 := &models.Track{ UserID: 123, Title: "Track 2", FilePath: "/test/track2.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Genre: "Jazz", Duration: 200, IsPublic: true, Status: models.TrackStatusCompleted, } err = db.Create(track2).Error assert.NoError(t, err) // Créer request req := httptest.NewRequest("GET", "/api/v1/tracks?page=1&limit=20", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) // Execute handler.ListTracks(c) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "tracks") assert.Contains(t, response, "pagination") tracks := response["tracks"].([]interface{}) assert.GreaterOrEqual(t, len(tracks), 2) pagination := response["pagination"].(map[string]interface{}) assert.Equal(t, float64(1), pagination["page"]) assert.Equal(t, float64(20), pagination["limit"]) } func TestTrackHandler_ListTracks_WithFilters(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer tracks avec différents genres track1 := &models.Track{ UserID: 123, Title: "Rock Track", FilePath: "/test/track1.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Genre: "Rock", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track1).Error assert.NoError(t, err) track2 := &models.Track{ UserID: 123, Title: "Jazz Track", FilePath: "/test/track2.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Genre: "Jazz", Duration: 200, IsPublic: true, Status: models.TrackStatusCompleted, } err = db.Create(track2).Error assert.NoError(t, err) // Test avec filtre genre req := httptest.NewRequest("GET", "/api/v1/tracks?genre=Rock", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) handler.ListTracks(c) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) tracks := response["tracks"].([]interface{}) assert.Equal(t, 1, len(tracks)) track := tracks[0].(map[string]interface{}) assert.Equal(t, "Rock", track["genre"]) } func TestTrackHandler_ListTracks_WithPagination(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer 5 tracks for i := 1; i <= 5; i++ { track := &models.Track{ UserID: 123, Title: "Track " + string(rune('0'+i)), FilePath: "/test/track" + string(rune('0'+i)) + ".mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error assert.NoError(t, err) } // Test page 1 avec limit 2 req := httptest.NewRequest("GET", "/api/v1/tracks?page=1&limit=2", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) handler.ListTracks(c) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) tracks := response["tracks"].([]interface{}) assert.Equal(t, 2, len(tracks)) pagination := response["pagination"].(map[string]interface{}) assert.Equal(t, float64(1), pagination["page"]) assert.Equal(t, float64(2), pagination["limit"]) assert.Equal(t, float64(5), pagination["total"]) } func TestTrackHandler_ListTracks_WithSorting(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer tracks avec différents titres track1 := &models.Track{ UserID: 123, Title: "A Track", FilePath: "/test/track1.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track1).Error assert.NoError(t, err) track2 := &models.Track{ UserID: 123, Title: "Z Track", FilePath: "/test/track2.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err = db.Create(track2).Error assert.NoError(t, err) // Test avec tri par titre asc req := httptest.NewRequest("GET", "/api/v1/tracks?sort_by=title&sort_order=asc", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) handler.ListTracks(c) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) tracks := response["tracks"].([]interface{}) assert.GreaterOrEqual(t, len(tracks), 2) // Vérifier que le tri est appliqué (A avant Z) firstTrack := tracks[0].(map[string]interface{}) assert.Equal(t, "A Track", firstTrack["title"]) } func TestTrackHandler_UpdateTrack_Success(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer un track track := &models.Track{ UserID: 123, Title: "Original Title", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Genre: "Rock", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error assert.NoError(t, err) // Créer request body updateData := map[string]interface{}{ "title": "Updated Title", "genre": "Jazz", } body, _ := json.Marshal(updateData) // Créer request req := httptest.NewRequest("PUT", fmt.Sprintf("/api/v1/tracks/%d", track.ID), bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: fmt.Sprintf("%d", track.ID)}} // Execute handler.UpdateTrack(c) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "track") updatedTrack := response["track"].(map[string]interface{}) assert.Equal(t, "Updated Title", updatedTrack["title"]) assert.Equal(t, "Jazz", updatedTrack["genre"]) } func TestTrackHandler_UpdateTrack_NotFound(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request body updateData := map[string]interface{}{ "title": "Updated Title", } body, _ := json.Marshal(updateData) // Créer request avec un ID qui n'existe pas req := httptest.NewRequest("PUT", "/api/v1/tracks/99999", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: "99999"}} // Execute handler.UpdateTrack(c) // Assert assert.Equal(t, http.StatusNotFound, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "track not found", response["error"]) } func TestTrackHandler_UpdateTrack_Forbidden(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer un track appartenant à l'utilisateur 123 track := &models.Track{ UserID: 123, Title: "Original Title", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error assert.NoError(t, err) // Créer request body updateData := map[string]interface{}{ "title": "Updated Title", } body, _ := json.Marshal(updateData) // Créer request avec un autre utilisateur (456) req := httptest.NewRequest("PUT", fmt.Sprintf("/api/v1/tracks/%d", track.ID), bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(456)) c.Params = gin.Params{gin.Param{Key: "id", Value: fmt.Sprintf("%d", track.ID)}} // Execute handler.UpdateTrack(c) // Assert assert.Equal(t, http.StatusForbidden, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "forbidden", response["error"]) } func TestTrackHandler_UpdateTrack_Unauthorized(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request body updateData := map[string]interface{}{ "title": "Updated Title", } body, _ := json.Marshal(updateData) // Créer request sans user_id req := httptest.NewRequest("PUT", "/api/v1/tracks/1", bytes.NewBuffer(body)) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req // Pas de user_id c.Params = gin.Params{gin.Param{Key: "id", Value: "1"}} // Execute handler.UpdateTrack(c) // Assert assert.Equal(t, http.StatusUnauthorized, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "unauthorized", response["error"]) } func TestTrackHandler_UpdateTrack_InvalidID(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request body updateData := map[string]interface{}{ "title": "Updated Title", } body, _ := json.Marshal(updateData) // Créer request avec un ID invalide req := httptest.NewRequest("PUT", "/api/v1/tracks/invalid", bytes.NewBuffer(body)) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: "invalid"}} // Execute handler.UpdateTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "invalid track id", response["error"]) } func TestTrackHandler_UpdateTrack_EmptyTitle(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer un track track := &models.Track{ UserID: 123, Title: "Original Title", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error assert.NoError(t, err) // Créer request body avec titre vide updateData := map[string]interface{}{ "title": "", } body, _ := json.Marshal(updateData) // Créer request req := httptest.NewRequest("PUT", fmt.Sprintf("/api/v1/tracks/%d", track.ID), bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: fmt.Sprintf("%d", track.ID)}} // Execute handler.UpdateTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response["error"], "title cannot be empty") } func TestTrackHandler_DeleteTrack_Success(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer un track track := &models.Track{ UserID: 123, 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 assert.NoError(t, err) // Créer request req := httptest.NewRequest("DELETE", fmt.Sprintf("/api/v1/tracks/%d", track.ID), nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: fmt.Sprintf("%d", track.ID)}} // Execute handler.DeleteTrack(c) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "track deleted successfully", response["message"]) // Vérifier que le track a été supprimé var deletedTrack models.Track err = db.First(&deletedTrack, track.ID).Error assert.Error(t, err) assert.Equal(t, gorm.ErrRecordNotFound, err) } func TestTrackHandler_DeleteTrack_NotFound(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request avec un ID qui n'existe pas req := httptest.NewRequest("DELETE", "/api/v1/tracks/99999", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: "99999"}} // Execute handler.DeleteTrack(c) // Assert assert.Equal(t, http.StatusNotFound, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "track not found", response["error"]) } func TestTrackHandler_DeleteTrack_Forbidden(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer un track appartenant à l'utilisateur 123 track := &models.Track{ UserID: 123, 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 assert.NoError(t, err) // Créer request avec un autre utilisateur (456) req := httptest.NewRequest("DELETE", fmt.Sprintf("/api/v1/tracks/%d", track.ID), nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(456)) c.Params = gin.Params{gin.Param{Key: "id", Value: fmt.Sprintf("%d", track.ID)}} // Execute handler.DeleteTrack(c) // Assert assert.Equal(t, http.StatusForbidden, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "forbidden", response["error"]) // Vérifier que le track n'a pas été supprimé var existingTrack models.Track err = db.First(&existingTrack, track.ID).Error assert.NoError(t, err) assert.Equal(t, track.ID, existingTrack.ID) } func TestTrackHandler_DeleteTrack_Unauthorized(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request sans user_id req := httptest.NewRequest("DELETE", "/api/v1/tracks/1", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req // Pas de user_id c.Params = gin.Params{gin.Param{Key: "id", Value: "1"}} // Execute handler.DeleteTrack(c) // Assert assert.Equal(t, http.StatusUnauthorized, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "unauthorized", response["error"]) } func TestTrackHandler_DeleteTrack_InvalidID(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request avec un ID invalide req := httptest.NewRequest("DELETE", "/api/v1/tracks/invalid", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: "invalid"}} // Execute handler.DeleteTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "invalid track id", response["error"]) } func TestTrackHandler_GetTrack_Success(t *testing.T) { handler, db, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer un track track := &models.Track{ UserID: 123, Title: "Test Track", FilePath: "/test/track.mp3", FileSize: 5 * 1024 * 1024, Format: "MP3", Genre: "Rock", Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, } err := db.Create(track).Error assert.NoError(t, err) // Créer request req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/tracks/%d", track.ID), nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: fmt.Sprintf("%d", track.ID)}} // Execute handler.GetTrack(c) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "track") retrievedTrack := response["track"].(map[string]interface{}) assert.Equal(t, float64(track.ID), retrievedTrack["id"]) assert.Equal(t, track.Title, retrievedTrack["title"]) } func TestTrackHandler_GetTrack_NotFound(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request avec un ID qui n'existe pas req := httptest.NewRequest("GET", "/api/v1/tracks/99999", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: "99999"}} // Execute handler.GetTrack(c) // Assert assert.Equal(t, http.StatusNotFound, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "track not found", response["error"]) } func TestTrackHandler_GetTrack_InvalidID(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request avec un ID invalide req := httptest.NewRequest("GET", "/api/v1/tracks/invalid", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{gin.Param{Key: "id", Value: "invalid"}} // Execute handler.GetTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "invalid track id", response["error"]) } func TestTrackHandler_GetTrack_MissingID(t *testing.T) { handler, _, cleanup := setupTestTrackHandler(t) defer cleanup() // Créer request sans ID req := httptest.NewRequest("GET", "/api/v1/tracks/", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req c.Set("user_id", int64(123)) c.Params = gin.Params{} // Execute handler.GetTrack(c) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "track id is required", response["error"]) }