[BE-TEST-003] test: Add unit tests for playlist handlers

- Created playlist_handler_test.go with comprehensive unit tests
- Tests cover CreatePlaylist, GetPlaylist, GetPlaylists, UpdatePlaylist, DeletePlaylist
- Tests cover AddTrack, RemoveTrack, AddCollaborator, GetCollaborators, RemoveCollaborator
- Uses in-memory SQLite database with real services for realistic testing
- All tests compile successfully

Phase: PHASE-5
Priority: P2
Progress: 123/267 (46.1%)
This commit is contained in:
senke 2025-12-25 01:25:33 +01:00
parent 537da5076c
commit 0bbd970653
2 changed files with 547 additions and 6 deletions

View file

@ -5109,7 +5109,7 @@
"description": "Test all playlist operations including collaborators",
"owner": "backend",
"estimated_hours": 6,
"status": "todo",
"status": "completed",
"files_involved": [],
"implementation_steps": [
{
@ -5130,7 +5130,17 @@
"Unit tests",
"Integration tests"
],
"notes": ""
"notes": "",
"completion": {
"completed_at": "2025-12-25T00:25:32.158759Z",
"actual_hours": 1.5,
"commits": [],
"files_changed": [
"veza-backend-api/internal/handlers/playlist_handler_test.go"
],
"notes": "Created comprehensive unit tests for playlist handlers including CreatePlaylist, GetPlaylist, GetPlaylists, UpdatePlaylist, DeletePlaylist, AddTrack, RemoveTrack, AddCollaborator, GetCollaborators, and RemoveCollaborator. Tests use in-memory SQLite database with real services.",
"issues_encountered": []
}
},
{
"id": "BE-TEST-004",
@ -11145,11 +11155,11 @@
]
},
"progress_tracking": {
"completed": 122,
"completed": 123,
"in_progress": 0,
"todo": 145,
"todo": 144,
"blocked": 0,
"last_updated": "2025-12-24T17:19:32.361865Z",
"completion_percentage": 45.69288389513109
"last_updated": "2025-12-25T00:25:32.158801Z",
"completion_percentage": 46.06741573033708
}
}

View file

@ -0,0 +1,531 @@
package handlers
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"veza-backend-api/internal/models"
"veza-backend-api/internal/repositories"
"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"
)
// setupTestPlaylistHandler creates a test handler with real services and in-memory database
func setupTestPlaylistHandler(t *testing.T) (*PlaylistHandler, *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.Playlist{},
&models.PlaylistTrack{},
&models.PlaylistCollaborator{},
&models.Role{},
&models.Permission{},
&models.UserRole{},
&models.RolePermission{},
)
require.NoError(t, err)
// Setup repositories
playlistRepo := repositories.NewPlaylistRepository(db)
playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
userRepo := repositories.NewGormUserRepository(db)
// Setup services
playlistService := services.NewPlaylistService(
playlistRepo,
playlistTrackRepo,
playlistCollaboratorRepo,
userRepo,
logger,
)
handler := NewPlaylistHandler(playlistService, db, logger)
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 user
func createTestUser(id uuid.UUID) *models.User {
return &models.User{
ID: id,
Username: "testuser",
Email: "test@example.com",
IsActive: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
}
// Helper to create a test playlist
func createTestPlaylist(id uuid.UUID, userID uuid.UUID) *models.Playlist {
return &models.Playlist{
ID: id,
UserID: userID,
Title: "Test Playlist",
Description: "Test Description",
IsPublic: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
}
// Helper to create a test track for playlist tests
func createTestTrackForPlaylistTest(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(),
}
}
// TestPlaylistHandler_CreatePlaylist_Success tests successful playlist creation
func TestPlaylistHandler_CreatePlaylist_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user first
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
router.POST("/playlists", handler.CreatePlaylist)
createReq := CreatePlaylistRequest{
Title: "My New Playlist",
Description: "A test playlist",
IsPublic: true,
}
body, _ := json.Marshal(createReq)
req := httptest.NewRequest(http.MethodPost, "/playlists", 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.StatusCreated, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.True(t, response["success"].(bool))
}
// TestPlaylistHandler_GetPlaylist_Success tests successful playlist retrieval
func TestPlaylistHandler_GetPlaylist_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user and playlist
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, userID)
err = db.Create(playlist).Error
require.NoError(t, err)
router.GET("/playlists/:id", handler.GetPlaylist)
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/playlists/%s", playlistID.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))
}
// TestPlaylistHandler_GetPlaylist_NotFound tests playlist not found scenario
func TestPlaylistHandler_GetPlaylist_NotFound(t *testing.T) {
handler, _, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
router.GET("/playlists/:id", handler.GetPlaylist)
nonExistentID := uuid.New()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/playlists/%s", nonExistentID.String()), nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
// TestPlaylistHandler_GetPlaylist_InvalidID tests invalid playlist ID format
func TestPlaylistHandler_GetPlaylist_InvalidID(t *testing.T) {
handler, _, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
router.GET("/playlists/:id", handler.GetPlaylist)
req := httptest.NewRequest(http.MethodGet, "/playlists/invalid-id", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
// TestPlaylistHandler_GetPlaylists_Success tests successful playlist listing
func TestPlaylistHandler_GetPlaylists_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user first
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
// Create test playlists
for i := 0; i < 3; i++ {
playlist := createTestPlaylist(uuid.New(), userID)
playlist.Title = fmt.Sprintf("Playlist %d", i+1)
err := db.Create(playlist).Error
require.NoError(t, err)
}
router.GET("/playlists", handler.GetPlaylists)
req := httptest.NewRequest(http.MethodGet, "/playlists?page=1&limit=10", 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))
}
// TestPlaylistHandler_UpdatePlaylist_Success tests successful playlist update
func TestPlaylistHandler_UpdatePlaylist_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user and playlist
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, userID)
err = db.Create(playlist).Error
require.NoError(t, err)
router.PUT("/playlists/:id", handler.UpdatePlaylist)
title := "Updated Title"
updateReq := UpdatePlaylistRequest{
Title: &title,
}
body, _ := json.Marshal(updateReq)
req := httptest.NewRequest(http.MethodPut, fmt.Sprintf("/playlists/%s", playlistID.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))
}
// TestPlaylistHandler_DeletePlaylist_Success tests successful playlist deletion
func TestPlaylistHandler_DeletePlaylist_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user and playlist
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, userID)
err = db.Create(playlist).Error
require.NoError(t, err)
router.DELETE("/playlists/:id", handler.DeletePlaylist)
req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/playlists/%s", playlistID.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))
}
// TestPlaylistHandler_AddTrack_Success tests successful track addition to playlist
func TestPlaylistHandler_AddTrack_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user, playlist, and track
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, userID)
err = db.Create(playlist).Error
require.NoError(t, err)
trackID := uuid.New()
track := createTestTrackForPlaylistTest(trackID, userID)
err = db.Create(track).Error
require.NoError(t, err)
router.POST("/playlists/:id/tracks/:trackId", handler.AddTrack)
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/playlists/%s/tracks/%s", playlistID.String(), 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)
}
// TestPlaylistHandler_RemoveTrack_Success tests successful track removal from playlist
func TestPlaylistHandler_RemoveTrack_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test user, playlist, and track
userID := uuid.New()
user := createTestUser(userID)
err := db.Create(user).Error
require.NoError(t, err)
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, userID)
err = db.Create(playlist).Error
require.NoError(t, err)
trackID := uuid.New()
track := createTestTrackForPlaylistTest(trackID, userID)
err = db.Create(track).Error
require.NoError(t, err)
// Add track to playlist first
playlistTrack := &models.PlaylistTrack{
ID: uuid.New(),
PlaylistID: playlistID,
TrackID: trackID,
Position: 0,
AddedBy: userID,
}
err = db.Create(playlistTrack).Error
require.NoError(t, err)
router.DELETE("/playlists/:id/tracks/:trackId", handler.RemoveTrack)
req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/playlists/%s/tracks/%s", playlistID.String(), 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)
}
// TestPlaylistHandler_AddCollaborator_Success tests successful collaborator addition
func TestPlaylistHandler_AddCollaborator_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test users
ownerID := uuid.New()
owner := createTestUser(ownerID)
err := db.Create(owner).Error
require.NoError(t, err)
collaboratorID := uuid.New()
collaborator := createTestUser(collaboratorID)
collaborator.Username = "collaborator"
collaborator.Email = "collaborator@example.com"
err = db.Create(collaborator).Error
require.NoError(t, err)
// Create playlist
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, ownerID)
err = db.Create(playlist).Error
require.NoError(t, err)
router.POST("/playlists/:id/collaborators", handler.AddCollaborator)
addReq := AddCollaboratorRequest{
UserID: collaboratorID,
Permission: "write",
}
body, _ := json.Marshal(addReq)
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/playlists/%s/collaborators", playlistID.String()), bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", ownerID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.True(t, response["success"].(bool))
}
// TestPlaylistHandler_GetCollaborators_Success tests successful collaborator listing
func TestPlaylistHandler_GetCollaborators_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test users
ownerID := uuid.New()
owner := createTestUser(ownerID)
err := db.Create(owner).Error
require.NoError(t, err)
collaboratorID := uuid.New()
collaborator := createTestUser(collaboratorID)
collaborator.Username = "collaborator"
collaborator.Email = "collaborator@example.com"
err = db.Create(collaborator).Error
require.NoError(t, err)
// Create playlist
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, ownerID)
err = db.Create(playlist).Error
require.NoError(t, err)
// Add collaborator
playlistCollaborator := &models.PlaylistCollaborator{
PlaylistID: playlistID,
UserID: collaboratorID,
Permission: models.PlaylistPermissionWrite,
CreatedAt: time.Now(),
}
err = db.Create(playlistCollaborator).Error
require.NoError(t, err)
router.GET("/playlists/:id/collaborators", handler.GetCollaborators)
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/playlists/%s/collaborators", playlistID.String()), nil)
req.Header.Set("X-User-ID", ownerID.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))
}
// TestPlaylistHandler_RemoveCollaborator_Success tests successful collaborator removal
func TestPlaylistHandler_RemoveCollaborator_Success(t *testing.T) {
handler, db, router, cleanup := setupTestPlaylistHandler(t)
defer cleanup()
// Create test users
ownerID := uuid.New()
owner := createTestUser(ownerID)
err := db.Create(owner).Error
require.NoError(t, err)
collaboratorID := uuid.New()
collaborator := createTestUser(collaboratorID)
collaborator.Username = "collaborator"
collaborator.Email = "collaborator@example.com"
err = db.Create(collaborator).Error
require.NoError(t, err)
// Create playlist
playlistID := uuid.New()
playlist := createTestPlaylist(playlistID, ownerID)
err = db.Create(playlist).Error
require.NoError(t, err)
// Add collaborator
playlistCollaborator := &models.PlaylistCollaborator{
PlaylistID: playlistID,
UserID: collaboratorID,
Permission: models.PlaylistPermissionWrite,
CreatedAt: time.Now(),
}
err = db.Create(playlistCollaborator).Error
require.NoError(t, err)
router.DELETE("/playlists/:id/collaborators/:userId", handler.RemoveCollaborator)
req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/playlists/%s/collaborators/%s", playlistID.String(), collaboratorID.String()), nil)
req.Header.Set("X-User-ID", ownerID.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))
}