package track import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" "time" "veza-backend-api/internal/models" "veza-backend-api/internal/services" "github.com/gin-gonic/gin" "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" ) // setupTestTrackHandler creates a test handler with real services and in-memory database func setupTestTrackHandler(t *testing.T) (*TrackHandler, *gorm.DB, *gin.Engine, func()) { gin.SetMode(gin.TestMode) logger := zaptest.NewLogger(t) // Setup in-memory SQLite database db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err) db.Exec("PRAGMA foreign_keys = ON") // Auto-migrate models err = db.AutoMigrate( &models.User{}, &models.Track{}, &models.TrackLike{}, &models.TrackComment{}, &models.TrackPlay{}, &models.TrackShare{}, &models.TrackHistory{}, &models.Role{}, &models.Permission{}, &models.UserRole{}, &models.RolePermission{}, &models.PlaybackAnalytics{}, ) require.NoError(t, err) // Setup services trackService := NewTrackService(db, logger, "/tmp/test-uploads") trackUploadService := services.NewTrackUploadService(db, logger) chunkService := services.NewTrackChunkService("/tmp/test-chunks", nil, logger) likeService := services.NewTrackLikeService(db, logger) streamService := services.NewStreamService("http://localhost:8082", logger) handler := NewTrackHandler( trackService, trackUploadService, chunkService, likeService, streamService, ) historyService := services.NewTrackHistoryService(db, logger) handler.SetHistoryService(historyService) router := gin.New() router.Use(func(c *gin.Context) { // Mock auth middleware - set user_id from header if present userIDStr := c.GetHeader("X-User-ID") if userIDStr != "" { uid, err := uuid.Parse(userIDStr) if err == nil { c.Set("user_id", uid) } } c.Next() }) cleanup := func() { // Database cleanup handled by test } return handler, db, router, cleanup } // Helper to create a test track func createTestTrack(id uuid.UUID, userID uuid.UUID) *models.Track { return &models.Track{ ID: id, UserID: userID, Title: "Test Track", Artist: "Test Artist", FilePath: "/tmp/test-uploads/test.mp3", Format: "mp3", FileSize: 1024, Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, CreatedAt: time.Now(), UpdatedAt: time.Now(), } } // TestTrackHandler_GetTrack_Success tests successful track retrieval func TestTrackHandler_GetTrack_Success(t *testing.T) { handler, db, router, cleanup := setupTestTrackHandler(t) defer cleanup() // Create a test user first userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", } err := db.Create(user).Error require.NoError(t, err) // Create a test track trackID := uuid.New() track := createTestTrack(trackID, userID) err = db.Create(track).Error require.NoError(t, err) router.GET("/tracks/:id", handler.GetTrack) req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/tracks/%s", trackID.String()), nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) require.NoError(t, err) assert.True(t, response["success"].(bool)) } // TestTrackHandler_GetTrack_NotFound tests track not found scenario func TestTrackHandler_GetTrack_NotFound(t *testing.T) { handler, _, router, cleanup := setupTestTrackHandler(t) defer cleanup() router.GET("/tracks/:id", handler.GetTrack) nonExistentID := uuid.New() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/tracks/%s", nonExistentID.String()), nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusNotFound, w.Code) } // TestTrackHandler_GetTrack_InvalidID tests invalid track ID format func TestTrackHandler_GetTrack_InvalidID(t *testing.T) { handler, _, router, cleanup := setupTestTrackHandler(t) defer cleanup() router.GET("/tracks/:id", handler.GetTrack) req := httptest.NewRequest(http.MethodGet, "/tracks/invalid-id", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) } // TestTrackHandler_ListTracks_Success tests successful track listing func TestTrackHandler_ListTracks_Success(t *testing.T) { handler, db, router, cleanup := setupTestTrackHandler(t) defer cleanup() // Create test user first userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", } err := db.Create(user).Error require.NoError(t, err) // Create test tracks for i := 0; i < 3; i++ { track := createTestTrack(uuid.New(), userID) track.Title = fmt.Sprintf("Track %d", i+1) err := db.Create(track).Error require.NoError(t, err) } router.GET("/tracks", handler.ListTracks) req := httptest.NewRequest(http.MethodGet, "/tracks?page=1&limit=10", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) require.NoError(t, err) assert.True(t, response["success"].(bool)) } // TestTrackHandler_UpdateTrack_Success tests successful track update func TestTrackHandler_UpdateTrack_Success(t *testing.T) { handler, db, router, cleanup := setupTestTrackHandler(t) defer cleanup() // Create test user and track userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", } err := db.Create(user).Error require.NoError(t, err) trackID := uuid.New() track := createTestTrack(trackID, userID) err = db.Create(track).Error require.NoError(t, err) router.Use(func(c *gin.Context) { c.Set("user_id", userID) c.Next() }) router.PUT("/tracks/:id", handler.UpdateTrack) updateReq := UpdateTrackRequest{ Title: stringPtr("Updated Title"), Artist: stringPtr("Updated Artist"), } body, _ := json.Marshal(updateReq) req := httptest.NewRequest(http.MethodPut, fmt.Sprintf("/tracks/%s", trackID.String()), bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", userID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) require.NoError(t, err) assert.True(t, response["success"].(bool)) } // TestTrackHandler_DeleteTrack_Success tests successful track deletion func TestTrackHandler_DeleteTrack_Success(t *testing.T) { handler, db, router, cleanup := setupTestTrackHandler(t) defer cleanup() // Create test user and track userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", } err := db.Create(user).Error require.NoError(t, err) trackID := uuid.New() track := createTestTrack(trackID, userID) err = db.Create(track).Error require.NoError(t, err) router.Use(func(c *gin.Context) { c.Set("user_id", userID) c.Next() }) router.DELETE("/tracks/:id", handler.DeleteTrack) req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/tracks/%s", trackID.String()), nil) req.Header.Set("X-User-ID", userID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) require.NoError(t, err) assert.True(t, response["success"].(bool)) } // TestTrackHandler_LikeTrack_Success tests successful track like func TestTrackHandler_LikeTrack_Success(t *testing.T) { handler, db, router, cleanup := setupTestTrackHandler(t) defer cleanup() // Create test user first userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", } err := db.Create(user).Error require.NoError(t, err) // Create test track trackID := uuid.New() track := createTestTrack(trackID, userID) err = db.Create(track).Error require.NoError(t, err) router.Use(func(c *gin.Context) { c.Set("user_id", userID) c.Next() }) router.POST("/tracks/:id/like", handler.LikeTrack) req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/tracks/%s/like", trackID.String()), nil) req.Header.Set("X-User-ID", userID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) } // TestTrackHandler_SearchTracks_Success tests successful track search func TestTrackHandler_SearchTracks_Success(t *testing.T) { handler, db, router, cleanup := setupTestTrackHandler(t) defer cleanup() // Setup search service searchService := services.NewTrackSearchService(db) handler.SetSearchService(searchService) // Create test user first userID := uuid.New() user := &models.User{ ID: userID, Username: "testuser", Email: "test@example.com", } err := db.Create(user).Error require.NoError(t, err) // Create test tracks track1 := createTestTrack(uuid.New(), userID) track1.Title = "Test Song" err = db.Create(track1).Error require.NoError(t, err) router.GET("/tracks/search", handler.SearchTracks) req := httptest.NewRequest(http.MethodGet, "/tracks/search?q=Test&limit=10&offset=0", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) } // Helper function to create string pointer func stringPtr(s string) *string { return &s }