- 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%)
531 lines
16 KiB
Go
531 lines
16 KiB
Go
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))
|
|
}
|
|
|