package handlers import ( "context" "net/http" "net/http/httptest" "testing" "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/mock" "go.uber.org/zap" ) // MockChatServiceForChatHandler mocks ChatService type MockChatServiceForChatHandler struct { mock.Mock } func (m *MockChatServiceForChatHandler) GenerateToken(userID uuid.UUID, username string) (*services.ChatTokenResponse, error) { args := m.Called(userID, username) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*services.ChatTokenResponse), args.Error(1) } func (m *MockChatServiceForChatHandler) GetStats(ctx context.Context) (*services.ChatStats, error) { args := m.Called(ctx) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*services.ChatStats), args.Error(1) } // MockUserServiceForChatHandler mocks UserService type MockUserServiceForChatHandler struct { mock.Mock } func (m *MockUserServiceForChatHandler) GetByID(_ context.Context, userID uuid.UUID) (*models.User, error) { args := m.Called(userID) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*models.User), args.Error(1) } func setupTestChatRouter(mockChatService *MockChatServiceForChatHandler, mockUserService *MockUserServiceForChatHandler) *gin.Engine { gin.SetMode(gin.TestMode) router := gin.New() logger := zap.NewNop() handler := NewChatHandlerWithInterface(mockChatService, mockUserService, logger) api := router.Group("/api/v1/chat") api.Use(func(c *gin.Context) { userIDStr := c.GetHeader("X-User-ID") if userIDStr != "" { uid, err := uuid.Parse(userIDStr) if err == nil { c.Set("user_id", uid) } } c.Next() }) { api.GET("/token", handler.GetToken) api.GET("/stats", handler.GetStats) } return router } func TestChatHandler_GetToken_Success(t *testing.T) { // Setup mockChatService := new(MockChatServiceForChatHandler) mockUserService := new(MockUserServiceForChatHandler) router := setupTestChatRouter(mockChatService, mockUserService) userID := uuid.New() username := "testuser" expectedToken := &services.ChatTokenResponse{ Token: "test-token-123", } user := &models.User{ ID: userID, Username: username, } mockUserService.On("GetByID", userID).Return(user, nil) mockChatService.On("GenerateToken", userID, username).Return(expectedToken, nil) // Execute req, _ := http.NewRequest("GET", "/api/v1/chat/token", nil) req.Header.Set("X-User-ID", userID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) mockChatService.AssertExpectations(t) mockUserService.AssertExpectations(t) } func TestChatHandler_GetToken_Unauthorized(t *testing.T) { // Setup mockChatService := new(MockChatServiceForChatHandler) mockUserService := new(MockUserServiceForChatHandler) router := setupTestChatRouter(mockChatService, mockUserService) // Execute - No X-User-ID header req, _ := http.NewRequest("GET", "/api/v1/chat/token", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusUnauthorized, w.Code) mockChatService.AssertNotCalled(t, "GenerateToken") mockUserService.AssertNotCalled(t, "GetByID") } func TestChatHandler_GetToken_UserServiceError(t *testing.T) { // Setup mockChatService := new(MockChatServiceForChatHandler) mockUserService := new(MockUserServiceForChatHandler) router := setupTestChatRouter(mockChatService, mockUserService) userID := uuid.New() expectedToken := &services.ChatTokenResponse{ Token: "test-token-123", } // UserService returns error, handler should use fallback username mockUserService.On("GetByID", userID).Return(nil, assert.AnError) mockChatService.On("GenerateToken", userID, mock.MatchedBy(func(username string) bool { return username == "user_"+userID.String() })).Return(expectedToken, nil) // Execute req, _ := http.NewRequest("GET", "/api/v1/chat/token", nil) req.Header.Set("X-User-ID", userID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) mockChatService.AssertExpectations(t) mockUserService.AssertExpectations(t) } func TestChatHandler_GetToken_ChatServiceError(t *testing.T) { // Setup mockChatService := new(MockChatServiceForChatHandler) mockUserService := new(MockUserServiceForChatHandler) router := setupTestChatRouter(mockChatService, mockUserService) userID := uuid.New() username := "testuser" user := &models.User{ ID: userID, Username: username, } mockUserService.On("GetByID", userID).Return(user, nil) mockChatService.On("GenerateToken", userID, username).Return(nil, assert.AnError) // Execute req, _ := http.NewRequest("GET", "/api/v1/chat/token", nil) req.Header.Set("X-User-ID", userID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusInternalServerError, w.Code) mockChatService.AssertExpectations(t) mockUserService.AssertExpectations(t) } func TestChatHandler_GetStats_Success(t *testing.T) { // Setup mockChatService := new(MockChatServiceForChatHandler) mockUserService := new(MockUserServiceForChatHandler) router := setupTestChatRouter(mockChatService, mockUserService) expectedStats := &services.ChatStats{ TotalMessages: 100, ActiveUsers: 10, } mockChatService.On("GetStats", mock.Anything).Return(expectedStats, nil) // Execute req, _ := http.NewRequest("GET", "/api/v1/chat/stats", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) mockChatService.AssertExpectations(t) } func TestChatHandler_GetStats_ServiceError(t *testing.T) { // Setup mockChatService := new(MockChatServiceForChatHandler) mockUserService := new(MockUserServiceForChatHandler) router := setupTestChatRouter(mockChatService, mockUserService) mockChatService.On("GetStats", mock.Anything).Return(nil, assert.AnError) // Execute req, _ := http.NewRequest("GET", "/api/v1/chat/stats", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusInternalServerError, w.Code) mockChatService.AssertExpectations(t) }