package middleware import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // MockRoleService est un mock du RoleService pour les tests RBAC // ImplĂ©mente l'interface RoleChecker pour ĂȘtre compatible avec RequireRole type MockRoleService struct { mock.Mock } func (m *MockRoleService) HasRole(ctx context.Context, userID int64, roleName string) (bool, error) { args := m.Called(ctx, userID, roleName) return args.Bool(0), args.Error(1) } func (m *MockRoleService) HasPermission(ctx context.Context, userID int64, resource, action string) (bool, error) { args := m.Called(ctx, userID, resource, action) return args.Bool(0), args.Error(1) } func TestRequireRole_WithValidRole(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasRole", mock.Anything, int64(123), "admin").Return(true, nil) router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", int64(123)) c.Next() }) router.Use(RequireRole(mockRoleService, "admin")) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) mockRoleService.AssertExpectations(t) } func TestRequireRole_WithInvalidRole(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasRole", mock.Anything, int64(123), "admin").Return(false, nil) handlerCalled := false router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", int64(123)) c.Next() }) router.Use(RequireRole(mockRoleService, "admin")) router.GET("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusForbidden, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") assert.Equal(t, "insufficient permissions", response["error"]) mockRoleService.AssertExpectations(t) } func TestRequireRole_WithoutUserID(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) handlerCalled := false router := gin.New() router.Use(RequireRole(mockRoleService, "admin")) router.GET("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() // user_id not set router.ServeHTTP(w, req) assert.Equal(t, http.StatusUnauthorized, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") assert.Equal(t, "unauthorized", response["error"]) mockRoleService.AssertNotCalled(t, "HasRole") } func TestRequireRole_WithServiceError(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasRole", mock.Anything, int64(123), "admin").Return(false, assert.AnError) handlerCalled := false router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", int64(123)) c.Next() }) router.Use(RequireRole(mockRoleService, "admin")) router.GET("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") mockRoleService.AssertExpectations(t) } func TestRequireRole_WithIntUserID(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasRole", mock.Anything, int64(123), "admin").Return(true, nil) router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", 123) // int instead of int64 c.Next() }) router.Use(RequireRole(mockRoleService, "admin")) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) mockRoleService.AssertExpectations(t) } func TestRequirePermission_WithValidPermission(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasPermission", mock.Anything, int64(123), "tracks", "create").Return(true, nil) router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", int64(123)) c.Next() }) router.Use(RequirePermission(mockRoleService, "tracks", "create")) router.POST("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodPost, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) mockRoleService.AssertExpectations(t) } func TestRequirePermission_WithInvalidPermission(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasPermission", mock.Anything, int64(123), "tracks", "delete").Return(false, nil) handlerCalled := false router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", int64(123)) c.Next() }) router.Use(RequirePermission(mockRoleService, "tracks", "delete")) router.DELETE("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodDelete, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusForbidden, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") assert.Equal(t, "insufficient permissions", response["error"]) mockRoleService.AssertExpectations(t) } func TestRequirePermission_WithoutUserID(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) handlerCalled := false router := gin.New() router.Use(RequirePermission(mockRoleService, "tracks", "create")) router.POST("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodPost, "/test", nil) w := httptest.NewRecorder() // user_id not set router.ServeHTTP(w, req) assert.Equal(t, http.StatusUnauthorized, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") assert.Equal(t, "unauthorized", response["error"]) mockRoleService.AssertNotCalled(t, "HasPermission") } func TestRequirePermission_WithServiceError(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasPermission", mock.Anything, int64(123), "tracks", "create").Return(false, assert.AnError) handlerCalled := false router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", int64(123)) c.Next() }) router.Use(RequirePermission(mockRoleService, "tracks", "create")) router.POST("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodPost, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") mockRoleService.AssertExpectations(t) } func TestRequirePermission_WithIntUserID(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) mockRoleService.On("HasPermission", mock.Anything, int64(123), "users", "manage").Return(true, nil) router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", 123) // int instead of int64 c.Next() }) router.Use(RequirePermission(mockRoleService, "users", "manage")) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) mockRoleService.AssertExpectations(t) } func TestRequirePermission_WithInvalidUserIDType(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) handlerCalled := false router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", "invalid") // Invalid type c.Next() }) router.Use(RequirePermission(mockRoleService, "tracks", "create")) router.POST("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodPost, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusUnauthorized, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") assert.Equal(t, "invalid user id type", response["error"]) mockRoleService.AssertNotCalled(t, "HasPermission") } func TestRequireRole_WithInvalidUserIDType(t *testing.T) { gin.SetMode(gin.TestMode) mockRoleService := new(MockRoleService) handlerCalled := false router := gin.New() router.Use(func(c *gin.Context) { c.Set("user_id", "invalid") // Invalid type c.Next() }) router.Use(RequireRole(mockRoleService, "admin")) router.GET("/test", func(c *gin.Context) { handlerCalled = true c.JSON(http.StatusOK, gin.H{"message": "success"}) }) req := httptest.NewRequest(http.MethodGet, "/test", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusUnauthorized, w.Code) assert.False(t, handlerCalled, "Handler should not be called") var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Contains(t, response, "error") assert.Equal(t, "invalid user id type", response["error"]) mockRoleService.AssertNotCalled(t, "HasRole") }