305 lines
9.8 KiB
Go
305 lines
9.8 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"veza-backend-api/internal/models"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// MockPlaylistService est un mock du PlaylistService pour les tests
|
|
type MockPlaylistService struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockPlaylistService) CheckPermission(ctx context.Context, playlistID, userID uuid.UUID, requiredPermission models.PlaylistPermission) (bool, error) {
|
|
args := m.Called(ctx, playlistID, userID, requiredPermission)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
// setupPlaylistPermissionTestRouter crée un router de test avec le middleware de permissions
|
|
func setupPlaylistPermissionTestRouter(t *testing.T) (*gin.Engine, *MockPlaylistService, func()) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
// Setup mock service
|
|
mockService := new(MockPlaylistService)
|
|
|
|
// Setup router
|
|
router := gin.New()
|
|
router.Use(func(c *gin.Context) {
|
|
// Mock authentication middleware - set user_id from query param
|
|
if userIDStr := c.Query("user_id"); userIDStr != "" {
|
|
if uid, err := uuid.Parse(userIDStr); err == nil {
|
|
c.Set("user_id", uid)
|
|
}
|
|
}
|
|
c.Next()
|
|
})
|
|
|
|
// Test endpoint
|
|
router.GET("/test/:id", CheckPlaylistPermission(mockService, models.PlaylistPermissionRead), func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"message": "success"})
|
|
})
|
|
|
|
cleanup := func() {
|
|
// Nothing to cleanup
|
|
}
|
|
|
|
return router, mockService, cleanup
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_Owner(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionRead).Return(true, nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
var response map[string]string
|
|
json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.Equal(t, "success", response["message"])
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_PublicRead(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionRead).Return(true, nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
var response map[string]string
|
|
json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.Equal(t, "success", response["message"])
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_PrivateForbidden(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionRead).Return(false, nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusForbidden, w.Code)
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
require.NoError(t, err)
|
|
// P0: Nouveau format AppError
|
|
errorObj, ok := response["error"].(map[string]interface{})
|
|
require.True(t, ok, "Error should be a map")
|
|
assert.Contains(t, errorObj["message"].(string), "forbidden")
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_CollaboratorRead(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionRead).Return(true, nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
var response map[string]string
|
|
json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.Equal(t, "success", response["message"])
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_CollaboratorWrite(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
mockService := new(MockPlaylistService)
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionWrite).Return(true, nil)
|
|
|
|
routerWrite := gin.New()
|
|
routerWrite.Use(func(c *gin.Context) {
|
|
if userIDStr := c.Query("user_id"); userIDStr != "" {
|
|
if uid, err := uuid.Parse(userIDStr); err == nil {
|
|
c.Set("user_id", uid)
|
|
}
|
|
}
|
|
c.Next()
|
|
})
|
|
routerWrite.GET("/test/:id", RequirePlaylistWrite(mockService), func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"message": "success"})
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
routerWrite.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_CollaboratorReadCannotWrite(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
mockService := new(MockPlaylistService)
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionWrite).Return(false, nil)
|
|
|
|
routerWrite := gin.New()
|
|
routerWrite.Use(func(c *gin.Context) {
|
|
if userIDStr := c.Query("user_id"); userIDStr != "" {
|
|
if uid, err := uuid.Parse(userIDStr); err == nil {
|
|
c.Set("user_id", uid)
|
|
}
|
|
}
|
|
c.Next()
|
|
})
|
|
routerWrite.GET("/test/:id", RequirePlaylistWrite(mockService), func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"message": "success"})
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
routerWrite.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusForbidden, w.Code)
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_NotFound(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
playlistID := uuid.New()
|
|
userID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, userID, models.PlaylistPermissionRead).Return(false, fmt.Errorf("playlist not found"))
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, userID), nil)
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
require.NoError(t, err)
|
|
// P0: Nouveau format AppError
|
|
errorObj, ok := response["error"].(map[string]interface{})
|
|
require.True(t, ok, "Error should be a map")
|
|
assert.Contains(t, errorObj["message"].(string), "playlist not found")
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_Unauthorized(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
playlistID := uuid.New()
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s", playlistID), nil) // Pas de user_id
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
require.NoError(t, err)
|
|
// P0: Nouveau format AppError
|
|
errorObj, ok := response["error"].(map[string]interface{})
|
|
require.True(t, ok, "Error should be a map")
|
|
assert.Contains(t, errorObj["message"].(string), "unauthorized")
|
|
mockService.AssertNotCalled(t, "CheckPermission")
|
|
}
|
|
|
|
func TestCheckPlaylistPermission_InvalidPlaylistID(t *testing.T) {
|
|
router, mockService, cleanup := setupPlaylistPermissionTestRouter(t)
|
|
defer cleanup()
|
|
|
|
userID := uuid.New()
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/invalid?user_id=%s", userID), nil)
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
require.NoError(t, err)
|
|
// P0: Nouveau format AppError
|
|
errorObj, ok := response["error"].(map[string]interface{})
|
|
require.True(t, ok, "Error should be a map")
|
|
assert.Contains(t, errorObj["message"].(string), "invalid playlist id")
|
|
mockService.AssertNotCalled(t, "CheckPermission")
|
|
}
|
|
|
|
func TestRequirePlaylistOwner(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
mockService := new(MockPlaylistService)
|
|
playlistID := uuid.New()
|
|
ownerID := uuid.New()
|
|
otherID := uuid.New()
|
|
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, ownerID, models.PlaylistPermissionAdmin).Return(true, nil)
|
|
mockService.On("CheckPermission", mock.Anything, playlistID, otherID, models.PlaylistPermissionAdmin).Return(false, nil)
|
|
|
|
routerOwner := gin.New()
|
|
routerOwner.Use(func(c *gin.Context) {
|
|
if userIDStr := c.Query("user_id"); userIDStr != "" {
|
|
if uid, err := uuid.Parse(userIDStr); err == nil {
|
|
c.Set("user_id", uid)
|
|
}
|
|
}
|
|
c.Next()
|
|
})
|
|
routerOwner.GET("/test/:id", RequirePlaylistOwner(mockService), func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"message": "success"})
|
|
})
|
|
|
|
// Owner peut accéder
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, ownerID), nil)
|
|
routerOwner.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
// Autre utilisateur ne peut pas accéder
|
|
w2 := httptest.NewRecorder()
|
|
req2 := httptest.NewRequest("GET", fmt.Sprintf("/test/%s?user_id=%s", playlistID, otherID), nil)
|
|
routerOwner.ServeHTTP(w2, req2)
|
|
assert.Equal(t, http.StatusForbidden, w2.Code)
|
|
|
|
mockService.AssertExpectations(t)
|
|
}
|