package examples import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "erp-mvp/core-service/internal/api/handlers" "erp-mvp/core-service/internal/api/middleware" "erp-mvp/core-service/internal/auth" "erp-mvp/core-service/internal/models" ) // MockAuthService мок для AuthService type MockAuthService struct { mock.Mock } func (m *MockAuthService) Register(ctx context.Context, req *models.RegisterRequest) (*models.LoginResponse, error) { args := m.Called(ctx, req) return args.Get(0).(*models.LoginResponse), args.Error(1) } func (m *MockAuthService) Login(ctx context.Context, req *models.LoginRequest) (*models.LoginResponse, error) { args := m.Called(ctx, req) return args.Get(0).(*models.LoginResponse), args.Error(1) } // TestAuthHandler_Register тестирует endpoint регистрации func TestAuthHandler_Register(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockAuthService := &MockAuthService{} handler := handlers.NewAuthHandler(mockAuthService) router := gin.New() router.POST("/register", handler.Register) registerReq := &models.RegisterRequest{ OrganizationName: "Test Workshop", UserEmail: "admin@test.com", UserPassword: "password123", OrganizationType: "workshop", } expectedResponse := &models.LoginResponse{ Token: "test_token", User: models.UserResponse{ ID: uuid.New(), Email: "admin@test.com", Role: "admin", }, Organization: models.OrganizationResponse{ ID: uuid.New(), Name: "Test Workshop", Type: "workshop", }, } mockAuthService.On("Register", mock.Anything, registerReq).Return(expectedResponse, nil) reqBody, _ := json.Marshal(registerReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/register", bytes.NewBuffer(reqBody)) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusCreated, w.Code) var response models.LoginResponse err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, expectedResponse.Token, response.Token) assert.Equal(t, expectedResponse.User.Email, response.User.Email) assert.Equal(t, expectedResponse.Organization.Name, response.Organization.Name) mockAuthService.AssertExpectations(t) } // TestAuthHandler_Login тестирует endpoint входа func TestAuthHandler_Login(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockAuthService := &MockAuthService{} handler := handlers.NewAuthHandler(mockAuthService) router := gin.New() router.POST("/login", handler.Login) loginReq := &models.LoginRequest{ Email: "admin@test.com", Password: "password123", } expectedResponse := &models.LoginResponse{ Token: "test_token", User: models.UserResponse{ ID: uuid.New(), Email: "admin@test.com", Role: "admin", }, Organization: models.OrganizationResponse{ ID: uuid.New(), Name: "Test Workshop", Type: "workshop", }, } mockAuthService.On("Login", mock.Anything, loginReq).Return(expectedResponse, nil) reqBody, _ := json.Marshal(loginReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/login", bytes.NewBuffer(reqBody)) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response models.LoginResponse err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, expectedResponse.Token, response.Token) mockAuthService.AssertExpectations(t) } // TestAuthHandler_Register_ValidationError тестирует валидацию при регистрации func TestAuthHandler_Register_ValidationError(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockAuthService := &MockAuthService{} handler := handlers.NewAuthHandler(mockAuthService) router := gin.New() router.POST("/register", handler.Register) // Неверный запрос - отсутствует email registerReq := map[string]interface{}{ "organization_name": "Test Workshop", "user_password": "password123", "organization_type": "workshop", } reqBody, _ := json.Marshal(registerReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/register", bytes.NewBuffer(reqBody)) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) var errorResponse map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &errorResponse) assert.NoError(t, err) assert.Contains(t, errorResponse["error"], "Validation failed") } // TestAuthMiddleware тестирует middleware аутентификации func TestAuthMiddleware(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) secret := "test_secret_key" ttl := 24 * time.Hour jwtService := auth.NewJWTService(secret, ttl) authMiddleware := middleware.NewAuthMiddleware(jwtService) router := gin.New() router.Use(authMiddleware.AuthRequired()) router.GET("/protected", func(c *gin.Context) { claims := middleware.GetClaims(c) c.JSON(http.StatusOK, gin.H{ "user_id": claims.UserID.String(), "organization_id": claims.OrganizationID.String(), "email": claims.Email, "role": claims.Role, }) }) // Создаем валидный JWT токен userID := uuid.New() orgID := uuid.New() validToken, err := jwtService.GenerateToken(userID, orgID, "test@example.com", "admin") assert.NoError(t, err) // Act - тест с валидным токеном w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer "+validToken) router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, userID.String(), response["user_id"]) assert.Equal(t, "test@example.com", response["email"]) // Act - тест без токена w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/protected", nil) router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusUnauthorized, w.Code) // Act - тест с неверным токеном w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/protected", nil) req.Header.Set("Authorization", "Bearer invalid_token") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusUnauthorized, w.Code) } // TestLocationHandler_CreateLocation тестирует создание места хранения func TestLocationHandler_CreateLocation(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockLocationService := &MockLocationService{} handler := handlers.NewLocationHandler(mockLocationService) router := gin.New() router.Use(mockAuthMiddleware()) router.POST("/locations", handler.CreateLocation) locationReq := &models.CreateLocationRequest{ Name: "Test Location", Address: "Test Address", Type: "warehouse", Coordinates: models.JSON{ "lat": 55.7558, "lng": 37.6176, }, } expectedLocation := &models.StorageLocation{ ID: uuid.New(), Name: "Test Location", Address: "Test Address", Type: "warehouse", Coordinates: models.JSON{ "lat": 55.7558, "lng": 37.6176, }, } mockLocationService.On("CreateLocation", mock.Anything, mock.Anything, locationReq).Return(expectedLocation, nil) reqBody, _ := json.Marshal(locationReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/locations", bytes.NewBuffer(reqBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer test_token") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusCreated, w.Code) var response models.StorageLocation err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, expectedLocation.Name, response.Name) assert.Equal(t, expectedLocation.Type, response.Type) mockLocationService.AssertExpectations(t) } // MockLocationService мок для LocationService type MockLocationService struct { mock.Mock } func (m *MockLocationService) CreateLocation(ctx context.Context, orgID uuid.UUID, req *models.CreateLocationRequest) (*models.StorageLocation, error) { args := m.Called(ctx, orgID, req) return args.Get(0).(*models.StorageLocation), args.Error(1) } func (m *MockLocationService) GetLocations(ctx context.Context, orgID uuid.UUID) ([]*models.StorageLocation, error) { args := m.Called(ctx, orgID) return args.Get(0).([]*models.StorageLocation), args.Error(1) } func (m *MockLocationService) GetLocation(ctx context.Context, id, orgID uuid.UUID) (*models.StorageLocation, error) { args := m.Called(ctx, id, orgID) return args.Get(0).(*models.StorageLocation), args.Error(1) } func (m *MockLocationService) UpdateLocation(ctx context.Context, id, orgID uuid.UUID, req *models.CreateLocationRequest) (*models.StorageLocation, error) { args := m.Called(ctx, id, orgID, req) return args.Get(0).(*models.StorageLocation), args.Error(1) } func (m *MockLocationService) DeleteLocation(ctx context.Context, id, orgID uuid.UUID) error { args := m.Called(ctx, id, orgID) return args.Error(0) } func (m *MockLocationService) GetChildren(ctx context.Context, parentID, orgID uuid.UUID) ([]*models.StorageLocation, error) { args := m.Called(ctx, parentID, orgID) return args.Get(0).([]*models.StorageLocation), args.Error(1) } // mockAuthMiddleware создает middleware для тестов func mockAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Устанавливаем тестовые claims claims := &auth.Claims{ UserID: uuid.New(), OrganizationID: uuid.New(), Email: "test@example.com", Role: "admin", } c.Set("user_id", claims.UserID) c.Set("organization_id", claims.OrganizationID) c.Set("email", claims.Email) c.Set("role", claims.Role) c.Next() } }