package handlers_test import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing" "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/models" ) // MockOperationsService мок для OperationsService type MockOperationsService struct { mock.Mock } func (m *MockOperationsService) PlaceItem(ctx context.Context, orgID uuid.UUID, req *models.PlaceItemRequest) (*models.ItemPlacement, error) { args := m.Called(ctx, orgID, req) return args.Get(0).(*models.ItemPlacement), args.Error(1) } func (m *MockOperationsService) MoveItem(ctx context.Context, placementID uuid.UUID, newLocationID uuid.UUID, orgID uuid.UUID) error { args := m.Called(ctx, placementID, newLocationID, orgID) return args.Error(0) } func (m *MockOperationsService) GetItemPlacements(ctx context.Context, itemID uuid.UUID, orgID uuid.UUID) ([]*models.ItemPlacement, error) { args := m.Called(ctx, itemID, orgID) return args.Get(0).([]*models.ItemPlacement), args.Error(1) } func (m *MockOperationsService) GetLocationPlacements(ctx context.Context, locationID uuid.UUID, orgID uuid.UUID) ([]*models.ItemPlacement, error) { args := m.Called(ctx, locationID, orgID) return args.Get(0).([]*models.ItemPlacement), args.Error(1) } func (m *MockOperationsService) UpdateQuantity(ctx context.Context, placementID uuid.UUID, quantity int, orgID uuid.UUID) error { args := m.Called(ctx, placementID, quantity, orgID) return args.Error(0) } func (m *MockOperationsService) DeletePlacement(ctx context.Context, placementID uuid.UUID, orgID uuid.UUID) error { args := m.Called(ctx, placementID, orgID) return args.Error(0) } func (m *MockOperationsService) Search(ctx context.Context, orgID uuid.UUID, req *models.SearchRequest) (*models.SearchResponse, error) { args := m.Called(ctx, orgID, req) return args.Get(0).(*models.SearchResponse), args.Error(1) } // TestNewOperationsHandler тестирует создание OperationsHandler func TestNewOperationsHandler(t *testing.T) { // Arrange mockService := &MockOperationsService{} // Act handler := handlers.NewOperationsHandler(mockService) // Assert assert.NotNil(t, handler) } // TestOperationsHandler_PlaceItem_Success тестирует успешное размещение товара func TestOperationsHandler_PlaceItem_Success(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockOperationsService := &MockOperationsService{} handler := handlers.NewOperationsHandler(mockOperationsService) orgID := uuid.New() itemID := uuid.New() locationID := uuid.New() placementID := uuid.New() placeReq := &models.PlaceItemRequest{ ItemID: itemID, LocationID: locationID, Quantity: 10, } expectedPlacement := &models.ItemPlacement{ ID: placementID, OrganizationID: orgID, ItemID: itemID, LocationID: locationID, Quantity: 10, } mockOperationsService.On("PlaceItem", mock.Anything, orgID, placeReq).Return(expectedPlacement, nil) router := gin.New() router.POST("/operations/place", func(c *gin.Context) { setClaims(c, orgID) handler.PlaceItem(c) }) reqBody, _ := json.Marshal(placeReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/operations/place", 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.ItemPlacement err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, itemID, response.ItemID) assert.Equal(t, locationID, response.LocationID) assert.Equal(t, 10, response.Quantity) mockOperationsService.AssertExpectations(t) } // TestOperationsHandler_PlaceItem_ValidationError тестирует ошибку валидации при размещении товара func TestOperationsHandler_PlaceItem_ValidationError(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockOperationsService := &MockOperationsService{} handler := handlers.NewOperationsHandler(mockOperationsService) orgID := uuid.New() // Невалидный запрос (отрицательное количество) invalidReq := map[string]interface{}{ "item_id": uuid.New().String(), "location_id": uuid.New().String(), "quantity": -5, // Отрицательное количество } router := gin.New() router.POST("/operations/place", func(c *gin.Context) { setClaims(c, orgID) handler.PlaceItem(c) }) reqBody, _ := json.Marshal(invalidReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/operations/place", bytes.NewBuffer(reqBody)) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusBadRequest, w.Code) mockOperationsService.AssertNotCalled(t, "PlaceItem") } // TestOperationsHandler_MoveItem_Success тестирует успешное перемещение товара func TestOperationsHandler_MoveItem_Success(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockOperationsService := &MockOperationsService{} handler := handlers.NewOperationsHandler(mockOperationsService) orgID := uuid.New() placementID := uuid.New() newLocationID := uuid.New() moveReq := map[string]interface{}{ "new_location_id": newLocationID.String(), } mockOperationsService.On("MoveItem", mock.Anything, placementID, newLocationID, orgID).Return(nil) router := gin.New() router.PUT("/operations/move/:id", func(c *gin.Context) { setClaims(c, orgID) handler.MoveItem(c) }) reqBody, _ := json.Marshal(moveReq) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("PUT", "/operations/move/"+placementID.String(), bytes.NewBuffer(reqBody)) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response map[string]string err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "Item moved successfully", response["message"]) mockOperationsService.AssertExpectations(t) } // TestOperationsHandler_GetItemPlacements_Success тестирует успешное получение размещений товара func TestOperationsHandler_GetItemPlacements_Success(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockOperationsService := &MockOperationsService{} handler := handlers.NewOperationsHandler(mockOperationsService) orgID := uuid.New() itemID := uuid.New() expectedPlacements := []*models.ItemPlacement{ { ID: uuid.New(), OrganizationID: orgID, ItemID: itemID, LocationID: uuid.New(), Quantity: 5, }, { ID: uuid.New(), OrganizationID: orgID, ItemID: itemID, LocationID: uuid.New(), Quantity: 3, }, } mockOperationsService.On("GetItemPlacements", mock.Anything, itemID, orgID).Return(expectedPlacements, nil) router := gin.New() router.GET("/operations/items/:item_id/placements", func(c *gin.Context) { setClaims(c, orgID) handler.GetItemPlacements(c) }) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/operations/items/"+itemID.String()+"/placements", nil) router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response []*models.ItemPlacement err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Len(t, response, 2) assert.Equal(t, itemID, response[0].ItemID) assert.Equal(t, itemID, response[1].ItemID) mockOperationsService.AssertExpectations(t) } // TestOperationsHandler_Search_Success тестирует успешный поиск func TestOperationsHandler_Search_Success(t *testing.T) { // Arrange gin.SetMode(gin.TestMode) mockOperationsService := &MockOperationsService{} handler := handlers.NewOperationsHandler(mockOperationsService) orgID := uuid.New() expectedResponse := &models.SearchResponse{ Items: []*models.ItemWithLocation{ { Item: models.Item{ ID: uuid.New(), OrganizationID: orgID, Name: "Test Item", Description: "Test Description", Category: "electronics", }, Location: models.StorageLocation{ ID: uuid.New(), OrganizationID: orgID, Name: "Test Location", Address: "Test Address", Type: "warehouse", }, Quantity: 5, }, }, TotalCount: 1, } mockOperationsService.On("Search", mock.Anything, orgID, mock.AnythingOfType("*models.SearchRequest")).Return(expectedResponse, nil) router := gin.New() router.GET("/operations/search", func(c *gin.Context) { setClaims(c, orgID) handler.Search(c) }) // Act w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/operations/search?q=test", nil) router.ServeHTTP(w, req) // Assert assert.Equal(t, http.StatusOK, w.Code) var response models.SearchResponse err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Len(t, response.Items, 1) assert.Equal(t, "Test Item", response.Items[0].Item.Name) assert.Equal(t, 1, response.TotalCount) mockOperationsService.AssertExpectations(t) }