From 280e9fb8656576e07a63648c7d9bf943e45b3d29 Mon Sep 17 00:00:00 2001 From: linuxMate Date: Thu, 28 Dec 2023 00:05:02 +0300 Subject: [PATCH 1/2] tags test fixx --- .../category/delivery/grpc/handlers_test.go | 263 +++---- .../category/delivery/http/handlers_test.go | 728 +++++++++--------- .../category/repository/postgres/postgres.go | 41 +- .../repository/postgres/postgres_test.go | 178 ++--- 4 files changed, 601 insertions(+), 609 deletions(-) diff --git a/internal/microservices/category/delivery/grpc/handlers_test.go b/internal/microservices/category/delivery/grpc/handlers_test.go index 6f40130..0e03acc 100644 --- a/internal/microservices/category/delivery/grpc/handlers_test.go +++ b/internal/microservices/category/delivery/grpc/handlers_test.go @@ -1,165 +1,166 @@ package grpc -// import ( -// "context" -// "errors" -// "github.com/go-park-mail-ru/2023_2_Hamster/internal/common/logger" -// proto "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/category/delivery/grpc/generated" -// mocks "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/category/mocks" -// "github.com/go-park-mail-ru/2023_2_Hamster/internal/models" -// "github.com/golang/mock/gomock" -// "github.com/golang/protobuf/ptypes/empty" -// "github.com/google/uuid" -// "github.com/stretchr/testify/assert" -// "testing" -// ) +import ( + "context" + "errors" + "testing" -// func TestCreateTag(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// expectedTagID := uuid.New() - -// request := &proto.CreateTagRequest{ -// UserId: expectedTagID.String(), -// ParentId: expectedTagID.String(), -// Name: "TestTag", -// ShowIncome: true, -// ShowOutcome: true, -// Regular: false, -// } + "github.com/go-park-mail-ru/2023_2_Hamster/internal/common/logger" + proto "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/category/delivery/grpc/generated" + mocks "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/category/mocks" + "github.com/go-park-mail-ru/2023_2_Hamster/internal/models" + "github.com/golang/mock/gomock" + "github.com/golang/protobuf/ptypes/empty" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) -// mockCategoryServices := mocks.NewMockUsecase(ctrl) -// mockCategoryServices.EXPECT(). -// CreateTag(gomock.Any(), gomock.Any()). -// Return(expectedTagID, nil) - -// categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) - -// response, err := categoryGRPC.CreateTag(context.Background(), request) - -// assert.NoError(t, err) -// assert.NotNil(t, response) -// assert.Equal(t, expectedTagID.String(), response.TagId) -// } +func TestCreateTag(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() -// func TestGetTags(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// expectedUserID := uuid.New() - -// request := &proto.UserIdRequest{ -// UserId: expectedUserID.String(), -// } - -// expectedTags := []models.Category{{}, {}} + expectedTagID := uuid.New() -// mockCategoryServices := mocks.NewMockUsecase(ctrl) -// mockCategoryServices.EXPECT(). -// GetTags(gomock.Any(), gomock.Any()). -// Return(expectedTags, nil) + request := &proto.CreateTagRequest{ + UserId: expectedTagID.String(), + ParentId: expectedTagID.String(), + Name: "TestTag", + ShowIncome: true, + ShowOutcome: true, + Regular: false, + } -// categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) + mockCategoryServices := mocks.NewMockUsecase(ctrl) + mockCategoryServices.EXPECT(). + CreateTag(gomock.Any(), gomock.Any()). + Return(expectedTagID, nil) -// response, err := categoryGRPC.GetTags(context.Background(), request) + categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) -// assert.NoError(t, err) -// assert.NotNil(t, response) -// assert.Len(t, response.Categories, len(expectedTags)) + response, err := categoryGRPC.CreateTag(context.Background(), request) -// } + assert.NoError(t, err) + assert.NotNil(t, response) + assert.Equal(t, expectedTagID.String(), response.TagId) +} -// func TestGetTags2(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() +func TestGetTags(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + expectedUserID := uuid.New() -// expectedUserID := uuid.New() + request := &proto.UserIdRequest{ + UserId: expectedUserID.String(), + } -// request := &proto.UserIdRequest{ -// UserId: expectedUserID.String(), -// } + expectedTags := []models.Category{{}, {}} -// expectedError := errors.New("some error message") + mockCategoryServices := mocks.NewMockUsecase(ctrl) + mockCategoryServices.EXPECT(). + GetTags(gomock.Any(), gomock.Any()). + Return(expectedTags, nil) -// mockCategoryServices := mocks.NewMockUsecase(ctrl) -// mockCategoryServices.EXPECT(). -// GetTags(gomock.Any(), gomock.Any()). -// Return(nil, expectedError) + categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) -// categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) + response, err := categoryGRPC.GetTags(context.Background(), request) -// response, err := categoryGRPC.GetTags(context.Background(), request) + assert.NoError(t, err) + assert.NotNil(t, response) + assert.Len(t, response.Categories, len(expectedTags)) -// assert.Error(t, err) -// assert.Nil(t, response) -// assert.Equal(t, expectedError, err) -// } +} -// func TestUpdateTag(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() +func TestGetTags2(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() -// expectedID := uuid.New() -// expectedUserID := uuid.New() -// expectedParentID := uuid.New() + expectedUserID := uuid.New() -// request := &proto.Category{ -// Id: expectedID.String(), -// UserId: expectedUserID.String(), -// ParentId: expectedParentID.String(), -// Name: "UpdatedTag", -// ShowIncome: true, -// ShowOutcome: false, -// Regular: true, -// } + request := &proto.UserIdRequest{ + UserId: expectedUserID.String(), + } -// mockCategoryServices := mocks.NewMockUsecase(ctrl) -// mockCategoryServices.EXPECT(). -// UpdateTag(gomock.Any(), gomock.Any()). -// Return(nil) // Предполагаем, что обновление прошло успешно. + expectedError := errors.New("some error message") -// categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) + mockCategoryServices := mocks.NewMockUsecase(ctrl) + mockCategoryServices.EXPECT(). + GetTags(gomock.Any(), gomock.Any()). + Return(nil, expectedError) -// response, err := categoryGRPC.UpdateTag(context.Background(), request) + categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) -// assert.NoError(t, err) -// assert.NotNil(t, response) + response, err := categoryGRPC.GetTags(context.Background(), request) -// // Проверим, что возвращенные данные соответствуют ожидаемым. -// assert.Equal(t, expectedID.String(), response.Id) -// assert.Equal(t, expectedUserID.String(), response.UserId) -// assert.Equal(t, expectedParentID.String(), response.ParentId) -// assert.Equal(t, request.Name, response.Name) -// assert.Equal(t, request.ShowIncome, response.ShowIncome) -// assert.Equal(t, request.ShowOutcome, response.ShowOutcome) -// assert.Equal(t, request.Regular, response.Regular) -// } + assert.Error(t, err) + assert.Nil(t, response) + assert.Equal(t, expectedError, err) +} -// func TestDeleteTag(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() +func TestUpdateTag(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() -// expectedTagID := uuid.New() -// expectedUserID := uuid.New() + expectedID := uuid.New() + expectedUserID := uuid.New() + expectedParentID := uuid.New() -// request := &proto.DeleteRequest{ -// TagId: expectedTagID.String(), -// UserId: expectedUserID.String(), -// } + request := &proto.Category{ + Id: expectedID.String(), + UserId: expectedUserID.String(), + ParentId: expectedParentID.String(), + Name: "UpdatedTag", + ShowIncome: true, + ShowOutcome: false, + Regular: true, + } -// mockCategoryServices := mocks.NewMockUsecase(ctrl) -// mockCategoryServices.EXPECT(). -// DeleteTag(gomock.Any(), expectedTagID, expectedUserID). -// Return(nil) // Предполагаем, что удаление прошло успешно. + mockCategoryServices := mocks.NewMockUsecase(ctrl) + mockCategoryServices.EXPECT(). + UpdateTag(gomock.Any(), gomock.Any()). + Return(nil) // Предполагаем, что обновление прошло успешно. -// categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) + categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) -// response, err := categoryGRPC.DeleteTag(context.Background(), request) + response, err := categoryGRPC.UpdateTag(context.Background(), request) -// assert.NoError(t, err) -// assert.NotNil(t, response) + assert.NoError(t, err) + assert.NotNil(t, response) -// // Проверим, что возвращенные данные соответствуют ожидаемым. -// assert.Equal(t, &empty.Empty{}, response) -// } + // Проверим, что возвращенные данные соответствуют ожидаемым. + assert.Equal(t, expectedID.String(), response.Id) + assert.Equal(t, expectedUserID.String(), response.UserId) + assert.Equal(t, expectedParentID.String(), response.ParentId) + assert.Equal(t, request.Name, response.Name) + assert.Equal(t, request.ShowIncome, response.ShowIncome) + assert.Equal(t, request.ShowOutcome, response.ShowOutcome) + assert.Equal(t, request.Regular, response.Regular) +} + +func TestDeleteTag(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + expectedTagID := uuid.New() + expectedUserID := uuid.New() + + request := &proto.DeleteRequest{ + TagId: expectedTagID.String(), + UserId: expectedUserID.String(), + } + + mockCategoryServices := mocks.NewMockUsecase(ctrl) + mockCategoryServices.EXPECT(). + DeleteTag(gomock.Any(), expectedTagID, expectedUserID). + Return(nil) // Предполагаем, что удаление прошло успешно. + + categoryGRPC := NewCategoryGRPC(mockCategoryServices, *logger.NewLogger(context.TODO())) + + response, err := categoryGRPC.DeleteTag(context.Background(), request) + + assert.NoError(t, err) + assert.NotNil(t, response) + + // Проверим, что возвращенные данные соответствуют ожидаемым. + assert.Equal(t, &empty.Empty{}, response) +} diff --git a/internal/microservices/category/delivery/http/handlers_test.go b/internal/microservices/category/delivery/http/handlers_test.go index e0f12f6..f59cbb0 100644 --- a/internal/microservices/category/delivery/http/handlers_test.go +++ b/internal/microservices/category/delivery/http/handlers_test.go @@ -1,355 +1,377 @@ package http -// func TestHandler_CreateTag(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// tests := []struct { -// name string -// user *models.User -// expectedCode int -// expectedBody string -// mockUsecaseFn func(usecase *mocks.MockCategoryServiceClient) -// requestPayload string -// }{ -// { -// name: "Successful Tag Creation", -// user: user, -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{"category_id":"` + uuidTest.String() + `"}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// mockUsecase.EXPECT().CreateTag(gomock.Any(), gomock.Any()).Return(&genCategory.CreateTagResponse{TagId: uuidTest.String()}, nil) -// }, -// requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, -// }, -// { -// name: "Invalid Request Body", -// user: user, -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"Corrupted request body can't unmarshal"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// requestPayload: `invalid_json`, -// }, -// { -// name: "Error in Tag Creation", -// user: user, -// expectedCode: http.StatusTooManyRequests, -// expectedBody: `{"status":429,"message":"Can't create tag"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// mockUsecase.EXPECT().CreateTag(gomock.Any(), gomock.Any()).Return(nil, errors.New("tag not created")) -// }, -// requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// mockService := mocks.NewMockCategoryServiceClient(ctrl) -// tt.mockUsecaseFn(mockService) - -// mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) - -// req := httptest.NewRequest("POST", "/api/tag/create", strings.NewReader(tt.requestPayload)) -// req.Header.Set("Content-Type", "application/json") - -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// } - -// recorder := httptest.NewRecorder() - -// mockHandler.CreateTag(recorder, req) - -// actual := strings.TrimSpace(recorder.Body.String()) - -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -// } - -// // func TestHandler_GetTags(t *testing.T) { -// // uuidTest := uuid.New() -// // user := &models.User{ID: uuidTest} -// // tests := []struct { -// // name string -// // user *models.User -// // expectedCode int -// // expectedBody string -// // mockUsecaseFn func(mockUsecase *mocks.MockCategoryServiceClient) -// // }{ -// // { -// // name: "Successful Get Tags", -// // user: user, -// // expectedCode: http.StatusOK, -// // expectedBody: `{"status":200,"body":[{"id":"` + uuidTest.String() + `","user_id":"` + uuidTest.String() + `","parent_id":"` + uuid.Nil.String() + `","name":"TestTag","show_income":true,"show_outcome":true,"regular":true}]}`, -// // mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// // mockUsecase.EXPECT().GetTags(gomock.Any(), gomock.Any()).Return(&genCategory.GetTagsResponse{ -// // Categories: []*genCategory.Category{ -// // { -// // Id: uuidTest.String(), -// // UserId: uuidTest.String(), -// // ParentId: "", -// // Name: "TestTag", -// // ShowIncome: true, -// // ShowOutcome: true, -// // Regular: true, -// // }, -// // }, -// // }, nil) -// // }, -// // }, -// // { -// // name: "Unauthorized Request", -// // user: nil, -// // expectedCode: http.StatusUnauthorized, -// // expectedBody: `{"status":401,"message":"unauthorized"}`, -// // mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// // }, -// // { -// // name: "Error in Get Tags", -// // user: user, -// // expectedCode: http.StatusTooManyRequests, -// // expectedBody: `{"status":429,"message":"Can't get tags"}`, -// // mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// // mockUsecase.EXPECT().GetTags(gomock.Any(), gomock.Any()).Return(nil, errors.New("error getting tags")) -// // }, -// // }, -// // } - -// // for _, tt := range tests { -// // t.Run(tt.name, func(t *testing.T) { -// // ctrl := gomock.NewController(t) -// // defer ctrl.Finish() - -// // mockService := mocks.NewMockCategoryServiceClient(ctrl) -// // tt.mockUsecaseFn(mockService) - -// // mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) - -// // req := httptest.NewRequest("GET", "/api/tags", nil) - -// // if tt.user != nil { -// // ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// // req = req.WithContext(ctx) -// // } - -// // recorder := httptest.NewRecorder() - -// // mockHandler.GetTags(recorder, req) - -// // actual := strings.TrimSpace(recorder.Body.String()) - -// // assert.Equal(t, tt.expectedCode, recorder.Code) -// // assert.Equal(t, tt.expectedBody, actual) -// // }) -// // } -// // } - -// func TestHandler_UpdateTag(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// tagID := uuid.New() -// tag := models.Category{ -// ID: tagID, -// UserID: uuidTest, -// ParentID: uuid.Nil, -// Name: "TestTag", -// ShowIncome: true, -// ShowOutcome: true, -// Regular: true, -// } - -// tests := []struct { -// name string -// user *models.User -// tag models.Category -// expectedCode int -// expectedBody string -// mockUsecaseFn func(mockUsecase *mocks.MockCategoryServiceClient) -// requestPayload string -// }{ -// { -// name: "Successful Tag Update", -// user: user, -// tag: tag, -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{"id":"` + tagID.String() + `","user_id":"` + uuidTest.String() + `","parent_id":"` + uuid.Nil.String() + `","name":"TestTag","show_income":true,"show_outcome":true,"regular":true}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// mockUsecase.EXPECT().UpdateTag(gomock.Any(), gomock.Any()).Return(&genCategory.Category{ -// Id: tagID.String(), -// UserId: uuidTest.String(), -// ParentId: "", -// Name: "TestTag", -// ShowIncome: true, -// ShowOutcome: true, -// Regular: true, -// }, nil) -// }, -// requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// tag: tag, -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, -// }, -// { -// name: "Invalid Request Body", -// user: user, -// tag: models.Category{}, -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"Corrupted request body can't unmarshal"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// requestPayload: `{"invalid_json": "missing_quote}`, // Invalid JSON string -// }, -// { -// name: "Error in Tag Update", -// user: user, -// tag: tag, -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"Can't Update tag"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// mockUsecase.EXPECT().UpdateTag(gomock.Any(), gomock.Any()).Return(nil, errors.New("tag not updated")) -// }, -// requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// mockService := mocks.NewMockCategoryServiceClient(ctrl) -// tt.mockUsecaseFn(mockService) - -// mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) -// reqBody := []byte(tt.requestPayload) - -// req := httptest.NewRequest("PUT", "/api/tag/update", bytes.NewReader(reqBody)) -// req.Header.Set("Content-Type", "application/json") - -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// } - -// recorder := httptest.NewRecorder() - -// mockHandler.UpdateTag(recorder, req) - -// actual := strings.TrimSpace(recorder.Body.String()) - -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -// } - -// func TestHandler_DeleteTag(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// tagID := uuid.New() - -// tests := []struct { -// name string -// user *models.User -// tagID uuid.UUID -// expectedCode int -// expectedBody string -// mockUsecaseFn func(mockUsecase *mocks.MockCategoryServiceClient) -// requestPayload string -// }{ -// { -// name: "Successful Tag Deletion", -// user: user, -// tagID: tagID, -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{"id":"` + tagID.String() + `"}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// mockUsecase.EXPECT().DeleteTag(gomock.Any(), &genCategory.DeleteRequest{ -// TagId: tagID.String(), -// UserId: user.ID.String(), -// }).Return(nil, nil) -// }, -// requestPayload: `{"id": "` + tagID.String() + `"}`, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// tagID: tagID, -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// requestPayload: `{"id": "` + tagID.String() + `"}`, -// }, -// { -// name: "Invalid Request Body", -// user: user, -// tagID: tagID, -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"Corupted request body can't unmarshal"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, -// requestPayload: `{"invalid_json": "missing_quote}`, // Invalid JSON string -// }, -// { -// name: "Error in Tag Deletion", -// user: user, -// tagID: tagID, -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"Can't Delete tag"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { -// mockUsecase.EXPECT().DeleteTag(gomock.Any(), &genCategory.DeleteRequest{ -// TagId: tagID.String(), -// UserId: user.ID.String(), -// }).Return(nil, errors.New("tag not deleted")) -// }, -// requestPayload: `{"id": "` + tagID.String() + `"}`, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() - -// mockService := mocks.NewMockCategoryServiceClient(ctrl) -// tt.mockUsecaseFn(mockService) - -// mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) -// reqBody := []byte(tt.requestPayload) - -// req := httptest.NewRequest("DELETE", "/api/tag/delete", bytes.NewReader(reqBody)) -// req.Header.Set("Content-Type", "application/json") - -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// } - -// recorder := httptest.NewRecorder() - -// mockHandler.DeleteTag(recorder, req) - -// actual := strings.TrimSpace(recorder.Body.String()) - -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -// } +import ( + "bytes" + "context" + "errors" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/go-park-mail-ru/2023_2_Hamster/internal/common/logger" + "github.com/go-park-mail-ru/2023_2_Hamster/internal/models" + "github.com/stretchr/testify/assert" + + genCategory "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/category/delivery/grpc/generated" + mocks "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/category/mocks" + + "github.com/golang/mock/gomock" + "github.com/google/uuid" +) + +func TestHandler_CreateTag(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tests := []struct { + name string + user *models.User + expectedCode int + expectedBody string + mockUsecaseFn func(usecase *mocks.MockCategoryServiceClient) + requestPayload string + }{ + { + name: "Successful Tag Creation", + user: user, + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{"category_id":"` + uuidTest.String() + `"}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().CreateTag(gomock.Any(), gomock.Any()).Return(&genCategory.CreateTagResponse{TagId: uuidTest.String()}, nil) + }, + requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, + }, + { + name: "Unauthorized Request", + user: nil, + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, + }, + { + name: "Invalid Request Body", + user: user, + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"Corrupted request body can't unmarshal"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + requestPayload: `invalid_json`, + }, + { + name: "Error in Tag Creation", + user: user, + expectedCode: http.StatusTooManyRequests, + expectedBody: `{"status":429,"message":"Can't create tag"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().CreateTag(gomock.Any(), gomock.Any()).Return(nil, errors.New("tag not created")) + }, + requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockCategoryServiceClient(ctrl) + tt.mockUsecaseFn(mockService) + + mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("POST", "/api/tag/create", strings.NewReader(tt.requestPayload)) + req.Header.Set("Content-Type", "application/json") + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.CreateTag(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_GetTags(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tests := []struct { + name string + user *models.User + expectedCode int + expectedBody string + mockUsecaseFn func(mockUsecase *mocks.MockCategoryServiceClient) + }{ + { + name: "Successful Get Tags", + user: user, + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":[{"id":"` + uuidTest.String() + `","user_id":"` + uuidTest.String() + `","parent_id":"` + uuid.Nil.String() + `","image_id":0,"name":"TestTag","show_income":true,"show_outcome":true,"regular":true}]}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().GetTags(gomock.Any(), gomock.Any()).Return(&genCategory.GetTagsResponse{ + Categories: []*genCategory.Category{ + { + Id: uuidTest.String(), + UserId: uuidTest.String(), + ParentId: "", + Name: "TestTag", + Image: 0, + ShowIncome: true, + ShowOutcome: true, + Regular: true, + }, + }, + }, nil) + }, + }, + { + name: "Unauthorized Request", + user: nil, + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + }, + { + name: "Error in Get Tags", + user: user, + expectedCode: http.StatusTooManyRequests, + expectedBody: `{"status":429,"message":"Can't get tags"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().GetTags(gomock.Any(), gomock.Any()).Return(nil, errors.New("error getting tags")) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockCategoryServiceClient(ctrl) + tt.mockUsecaseFn(mockService) + + mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("GET", "/api/tags", nil) + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.GetTags(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_UpdateTag(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tagID := uuid.New() + tag := models.Category{ + ID: tagID, + UserID: uuidTest, + ParentID: uuid.Nil, + Name: "TestTag", + ShowIncome: true, + ShowOutcome: true, + Regular: true, + } + + tests := []struct { + name string + user *models.User + tag models.Category + expectedCode int + expectedBody string + mockUsecaseFn func(mockUsecase *mocks.MockCategoryServiceClient) + requestPayload string + }{ + { + name: "Successful Tag Update", + user: user, + tag: tag, + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{"id":"` + tagID.String() + `","user_id":"` + uuidTest.String() + `","parent_id":"` + uuid.Nil.String() + `","image_id":10,"name":"TestTag","show_income":true,"show_outcome":true,"regular":true}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().UpdateTag(gomock.Any(), gomock.Any()).Return(&genCategory.Category{ + Id: tagID.String(), + UserId: uuidTest.String(), + ParentId: "", + Name: "TestTag", + Image: 10, + ShowIncome: true, + ShowOutcome: true, + Regular: true, + }, nil) + }, + requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, + }, + { + name: "Unauthorized Request", + user: nil, + tag: tag, + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, + }, + { + name: "Invalid Request Body", + user: user, + tag: models.Category{}, + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"Corrupted request body can't unmarshal"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + requestPayload: `{"invalid_json": "missing_quote}`, // Invalid JSON string + }, + { + name: "Error in Tag Update", + user: user, + tag: tag, + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"Can't Update tag"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().UpdateTag(gomock.Any(), gomock.Any()).Return(nil, errors.New("tag not updated")) + }, + requestPayload: `{"name": "TestTag", "showIncome": true, "showOutcome": true, "regular": true}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockCategoryServiceClient(ctrl) + tt.mockUsecaseFn(mockService) + + mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) + reqBody := []byte(tt.requestPayload) + + req := httptest.NewRequest("PUT", "/api/tag/update", bytes.NewReader(reqBody)) + req.Header.Set("Content-Type", "application/json") + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.UpdateTag(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_DeleteTag(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tagID := uuid.New() + + tests := []struct { + name string + user *models.User + tagID uuid.UUID + expectedCode int + expectedBody string + mockUsecaseFn func(mockUsecase *mocks.MockCategoryServiceClient) + requestPayload string + }{ + { + name: "Successful Tag Deletion", + user: user, + tagID: tagID, + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{"id":"` + tagID.String() + `"}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().DeleteTag(gomock.Any(), &genCategory.DeleteRequest{ + TagId: tagID.String(), + UserId: user.ID.String(), + }).Return(nil, nil) + }, + requestPayload: `{"id": "` + tagID.String() + `"}`, + }, + { + name: "Unauthorized Request", + user: nil, + tagID: tagID, + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + requestPayload: `{"id": "` + tagID.String() + `"}`, + }, + { + name: "Invalid Request Body", + user: user, + tagID: tagID, + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"Corupted request body can't unmarshal"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) {}, + requestPayload: `{"invalid_json": "missing_quote}`, // Invalid JSON string + }, + { + name: "Error in Tag Deletion", + user: user, + tagID: tagID, + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"Can't Delete tag"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockCategoryServiceClient) { + mockUsecase.EXPECT().DeleteTag(gomock.Any(), &genCategory.DeleteRequest{ + TagId: tagID.String(), + UserId: user.ID.String(), + }).Return(nil, errors.New("tag not deleted")) + }, + requestPayload: `{"id": "` + tagID.String() + `"}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockCategoryServiceClient(ctrl) + tt.mockUsecaseFn(mockService) + + mockHandler := NewHandler(mockService, *logger.NewLogger(context.TODO())) + reqBody := []byte(tt.requestPayload) + + req := httptest.NewRequest("DELETE", "/api/tag/delete", bytes.NewReader(reqBody)) + req.Header.Set("Content-Type", "application/json") + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.DeleteTag(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} diff --git a/internal/microservices/category/repository/postgres/postgres.go b/internal/microservices/category/repository/postgres/postgres.go index 64e4564..f937e5c 100644 --- a/internal/microservices/category/repository/postgres/postgres.go +++ b/internal/microservices/category/repository/postgres/postgres.go @@ -34,8 +34,6 @@ const ( SELECT "name" FROM category WHERE user_id = $1 AND id = $2 );` - - // transactionAssociationDelete = "DELETE FROM TransactionCategory WHERE category_id = $1;" ) type Repository struct { @@ -76,16 +74,6 @@ func (r *Repository) CreateTag(ctx context.Context, tag models.Category) (uuid.U } func (r *Repository) UpdateTag(ctx context.Context, tag *models.Category) error { - /*var exists bool - - row := r.db.QueryRow(ctx, CategoryGet, tag.ID) - err := row.Scan(&exists) - if errors.Is(err, sql.ErrNoRows) { - return fmt.Errorf("[repo] Error tag doesn't exist: %w", err) - } else if err != nil { - return fmt.Errorf("[repo] failed request db %s, %w", CategoryGet, err) - } */ - var parentID interface{} if tag.ParentID != uuid.Nil { parentID = tag.ParentID @@ -107,17 +95,6 @@ func (r *Repository) UpdateTag(ctx context.Context, tag *models.Category) error } func (r *Repository) DeleteTag(ctx context.Context, tagId uuid.UUID) error { - /*var exists bool - - row := r.db.QueryRow(ctx, CategoryGet, tagId) - err := row.Scan(&exists) - if errors.Is(err, sql.ErrNoRows) { - return fmt.Errorf("[repo] tag doesn't exist Error: %v", err) - } else if err != nil { - return fmt.Errorf("[repo] failed request db %s, %w", CategoryGet, err) - } - */ - tx, err := r.db.Begin(ctx) if err != nil { return fmt.Errorf("[repo] failed to start db transaction: %w", err) @@ -131,10 +108,6 @@ func (r *Repository) DeleteTag(ctx context.Context, tagId uuid.UUID) error { } }() - //if err = r.deleteTransactionAssociations(ctx, tx, tagId); err != nil { - // return err - //} - _, err = r.db.Exec(ctx, CategoryDelete, tagId) if err != nil { return fmt.Errorf("[repo] failed to delete category %s, %w", CategoryDelete, err) @@ -148,6 +121,7 @@ func (r *Repository) DeleteTag(ctx context.Context, tagId uuid.UUID) error { func (r *Repository) GetTags(ctx context.Context, userID uuid.UUID) ([]models.Category, error) { var categories []models.Category + var imageId int rows, err := r.db.Query(ctx, CategoeyAll, userID) if err != nil { @@ -161,7 +135,7 @@ func (r *Repository) GetTags(ctx context.Context, userID uuid.UUID) ([]models.Ca &tag.UserID, &tag.ParentID, &tag.Name, - &tag.Image, + &imageId, &tag.ShowIncome, &tag.ShowOutcome, &tag.Regular, @@ -169,6 +143,8 @@ func (r *Repository) GetTags(ctx context.Context, userID uuid.UUID) ([]models.Ca return nil, err } + tag.Image = int32(imageId) + categories = append(categories, tag) } @@ -207,12 +183,3 @@ func (r *Repository) CheckExist(ctx context.Context, userId uuid.UUID, tagId uui } return true, nil } - -// -// func (r *Repository) deleteTransactionAssociations(ctx context.Context, tx pgx.Tx, tagID uuid.UUID) error { -// _, err := tx.Exec(ctx, transactionAssociationDelete, tagID) -// if err != nil { -// return fmt.Errorf("[repo] failed to delete existing transaction associations: %w", err) -// } -// return nil -// } diff --git a/internal/microservices/category/repository/postgres/postgres_test.go b/internal/microservices/category/repository/postgres/postgres_test.go index 42ff621..70f22e7 100644 --- a/internal/microservices/category/repository/postgres/postgres_test.go +++ b/internal/microservices/category/repository/postgres/postgres_test.go @@ -2,8 +2,10 @@ package postgres import ( "context" + "database/sql" "errors" "fmt" + "reflect" "regexp" "testing" @@ -138,94 +140,94 @@ func Test_UpdateTag(t *testing.T) { } } -// func Test_GetTags(t *testing.T) { -// tagId := uuid.New() -// userId := uuid.New() -// parentId := uuid.New() -// testCases := []struct { -// name string -// userID uuid.UUID -// rows *pgxmock.Rows -// rowsError error -// expected []models.Category -// expectedErr error -// }{ -// { -// name: "Success", -// userID: uuid.New(), -// rows: pgxmock.NewRows([]string{"id", "user_id", "parent_id", "name", "image_id", "show_income", "show_outcome", "regular"}). -// AddRow(tagId, userId, parentId, "Tag1", 1, true, true, true). -// AddRow(tagId, userId, parentId, "Tag2", 1, false, true, false), -// rowsError: nil, -// expected: []models.Category{{ -// ID: tagId, -// UserID: userId, -// ParentID: parentId, -// Name: "Tag1", -// Image: 1, -// ShowIncome: true, -// ShowOutcome: true, -// Regular: true, -// }, { -// ID: tagId, -// UserID: userId, -// ParentID: parentId, -// Name: "Tag2", -// Image: 1, -// ShowIncome: false, -// ShowOutcome: true, -// Regular: false, -// }, -// }, -// expectedErr: nil, -// }, -// { -// name: "NoTagsFound", -// userID: uuid.New(), -// rows: pgxmock.NewRows([]string{}), -// rowsError: sql.ErrNoRows, -// expected: nil, -// expectedErr: fmt.Errorf("[repo] Error no tags found: %v", sql.ErrNoRows), -// }, -// { -// name: "RowsError", -// userID: uuid.New(), -// rows: pgxmock.NewRows([]string{}).RowError(0, errors.New("SOME ERROR")), -// rowsError: nil, -// expected: nil, -// expectedErr: fmt.Errorf("[repo] Error rows error: %v", errors.New("SOME ERROR")), -// }, -// } - -// for _, tc := range testCases { -// t.Run(tc.name, func(t *testing.T) { -// mock, _ := pgxmock.NewPool() - -// logger := *logger.NewLogger(context.TODO()) -// repo := NewRepository(mock, logger) - -// escapedQuery := regexp.QuoteMeta(CategoeyAll) -// mock.ExpectQuery(escapedQuery). -// WithArgs(tc.userID). -// WillReturnRows(tc.rows). -// WillReturnError(tc.rowsError) - -// result, err := repo.GetTags(context.Background(), tc.userID) - -// if (tc.expectedErr == nil && err != nil) || (tc.expectedErr != nil && err == nil) || (tc.expectedErr != nil && err != nil && tc.expectedErr.Error() != err.Error()) { -// t.Errorf("Expected error: %v, but got: %v", tc.expectedErr, err) -// } - -// if !reflect.DeepEqual(tc.expected, result) { -// t.Errorf("Expected tags: %v, but got: %v", tc.expected, result) -// } - -// if err := mock.ExpectationsWereMet(); err != nil { -// t.Errorf("There were unfulfilled expectations: %s", err) -// } -// }) -// } -// } +func Test_GetTags(t *testing.T) { + tagId := uuid.New() + userId := uuid.New() + parentId := uuid.New() + testCases := []struct { + name string + userID uuid.UUID + rows *pgxmock.Rows + rowsError error + expected []models.Category + expectedErr error + }{ + { + name: "Success", + userID: uuid.New(), + rows: pgxmock.NewRows([]string{"id", "user_id", "parent_id", "name", "image_id", "show_income", "show_outcome", "regular"}). + AddRow(tagId, userId, parentId, "Tag1", 1, true, true, true). + AddRow(tagId, userId, parentId, "Tag2", 115, false, true, false), + rowsError: nil, + expected: []models.Category{{ + ID: tagId, + UserID: userId, + ParentID: parentId, + Name: "Tag1", + Image: 1, + ShowIncome: true, + ShowOutcome: true, + Regular: true, + }, { + ID: tagId, + UserID: userId, + ParentID: parentId, + Name: "Tag2", + Image: 115, + ShowIncome: false, + ShowOutcome: true, + Regular: false, + }, + }, + expectedErr: nil, + }, + { + name: "NoTagsFound", + userID: uuid.New(), + rows: pgxmock.NewRows([]string{}), + rowsError: sql.ErrNoRows, + expected: nil, + expectedErr: fmt.Errorf("[repo] Error no tags found: %v", sql.ErrNoRows), + }, + { + name: "RowsError", + userID: uuid.New(), + rows: pgxmock.NewRows([]string{}).RowError(0, errors.New("SOME ERROR")), + rowsError: nil, + expected: nil, + expectedErr: fmt.Errorf("[repo] Error rows error: %v", errors.New("SOME ERROR")), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mock, _ := pgxmock.NewPool() + + logger := *logger.NewLogger(context.TODO()) + repo := NewRepository(mock, logger) + + escapedQuery := regexp.QuoteMeta(CategoeyAll) + mock.ExpectQuery(escapedQuery). + WithArgs(tc.userID). + WillReturnRows(tc.rows). + WillReturnError(tc.rowsError) + + result, err := repo.GetTags(context.Background(), tc.userID) + + if (tc.expectedErr == nil && err != nil) || (tc.expectedErr != nil && err == nil) || (tc.expectedErr != nil && err != nil && tc.expectedErr.Error() != err.Error()) { + t.Errorf("Expected error: %v, but got: %v", tc.expectedErr, err) + } + + if !reflect.DeepEqual(tc.expected, result) { + t.Errorf("Expected tags: %v, but got: %v", tc.expected, result) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("There were unfulfilled expectations: %s", err) + } + }) + } +} func Test_CheckNameUniq(t *testing.T) { testCases := []struct { From 5614a01479b558b789cdcca19b1a0ce09e10b4b7 Mon Sep 17 00:00:00 2001 From: linuxMate Date: Thu, 28 Dec 2023 01:24:31 +0300 Subject: [PATCH 2/2] export update && test add --- .../IOhub/delivery/http/handler.go | 31 +- .../delivery/http/handlers_test.go | 1608 +++++++++-------- .../repository/postgresql/postgres_test.go | 832 +++++---- .../microservices/user/mocks/user_mock.go | 15 + 4 files changed, 1264 insertions(+), 1222 deletions(-) diff --git a/internal/microservices/IOhub/delivery/http/handler.go b/internal/microservices/IOhub/delivery/http/handler.go index 21747aa..f7a5017 100644 --- a/internal/microservices/IOhub/delivery/http/handler.go +++ b/internal/microservices/IOhub/delivery/http/handler.go @@ -229,6 +229,7 @@ func (h *Handler) ImportTransactions(w http.ResponseWriter, r *http.Request) { ShowIncome: gtag.ShowIncome, ShowOutcome: gtag.ShowOutcome, Regular: gtag.Regular, + Image: gtag.Image, } tags[i] = tag } @@ -237,12 +238,13 @@ func (h *Handler) ImportTransactions(w http.ResponseWriter, r *http.Request) { tagCache := sync.Map{} if len(tags) != 0 { for _, tag := range tags { - accountCache.Store(tag.Name, tag.ID) + tagCache.Store(tag.Name, tag.ID) } } + var i int // Iterate through the records - for { + for i = 0; true; i++ { // Read each record from csv record, err := reader.Read() if err == io.EOF { @@ -253,18 +255,33 @@ func (h *Handler) ImportTransactions(w http.ResponseWriter, r *http.Request) { return } + if len(record) < 7 { + response.ErrorResponse(w, http.StatusBadRequest, err, "wrong format not enough args for transaction", h.logger) + return + } + + if len(record) > 8 { + response.ErrorResponse(w, http.StatusBadRequest, err, "wrong format too much args for transaction", h.logger) + return + } + accountIncome := record[0] accountOutcome := record[1] income, err := strconv.ParseFloat(record[2], 64) if err != nil { - response.ErrorResponse(w, http.StatusBadRequest, err, "Error converting the amount to float", h.logger) + response.ErrorResponse(w, http.StatusBadRequest, err, "Error converting the income amount to float", h.logger) return } outcome, err := strconv.ParseFloat(record[3], 64) if err != nil { - response.ErrorResponse(w, http.StatusBadRequest, err, "Error converting the amount to float", h.logger) + response.ErrorResponse(w, http.StatusBadRequest, err, "Error converting the outcome amount to float", h.logger) + return + } + + if (income == 0) == (outcome == 0) { + response.ErrorResponse(w, http.StatusBadRequest, err, "transaction can be consumables or profitable", h.logger) return } @@ -324,6 +341,7 @@ func (h *Handler) ImportTransactions(w http.ResponseWriter, r *http.Request) { tag, err := h.tagService.CreateTag(r.Context(), &generated.CreateTagRequest{ UserId: user.ID.String(), Name: tagName, + Image: 0, ShowIncome: false, Regular: false, ShowOutcome: true, @@ -362,5 +380,10 @@ func (h *Handler) ImportTransactions(w http.ResponseWriter, r *http.Request) { } } + if i == 0 { + response.ErrorResponse(w, http.StatusBadRequest, err, "empty file", h.logger) + return + } + response.SuccessResponse(w, http.StatusOK, "Successfully imported transactions") } diff --git a/internal/microservices/transaction/delivery/http/handlers_test.go b/internal/microservices/transaction/delivery/http/handlers_test.go index bef1d93..9be643d 100644 --- a/internal/microservices/transaction/delivery/http/handlers_test.go +++ b/internal/microservices/transaction/delivery/http/handlers_test.go @@ -1,803 +1,809 @@ package http -// -//import ( -// "context" -// "errors" -// "io" -// "net/http" -// "net/http/httptest" -// "strings" -// "testing" -// -// "github.com/go-park-mail-ru/2023_2_Hamster/internal/common/logger" -// mockClient "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/account/mocks" -// mocks "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/transaction/mocks" -// mockUser "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/user/mocks" -// "github.com/go-park-mail-ru/2023_2_Hamster/internal/models" -// "github.com/golang/mock/gomock" -// "github.com/google/uuid" -// "github.com/gorilla/mux" -// "github.com/stretchr/testify/assert" -//) -// -//func TestHandler_GetCount(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// tests := []struct { -// name string -// user *models.User -// expectedCode int -// expectedBody string -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Successful call to Get count", -// user: user, -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{"count":1}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().GetCount(gomock.Any(), gomock.Any()).Return(1, nil) -// }, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// // No service calls are expected for unauthorized request. -// }, -// }, -// { -// name: "Internal request Error", -// user: user, -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"can't get count transaction info"}`, -// mockUsecaseFn: func(mockService *mocks.MockUsecase) { -// internalServerError := errors.New("can't get feed info") -// mockService.EXPECT().GetCount(gomock.Any(), gomock.Any()).Return(1, internalServerError) -// }, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// req := httptest.NewRequest("GET", "/api/user/balance", nil) -// -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// } -// -// recorder := httptest.NewRecorder() -// -// mockHandler.GetCount(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -//} -// -//func TestHandler_GetFeed(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// tests := []struct { -// name string -// user *models.User -// queryParam string -// expectedCode int -// expectedBody string -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Successful call to GetFeed", -// user: user, -// queryParam: "page=2&page_size=10", -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{"transactions":[{"id":"00000000-0000-0000-0000-000000000000","account_income":"00000000-0000-0000-0000-000000000000","account_outcome":"00000000-0000-0000-0000-000000000000","income":0,"user_id":"` + user.ID.String() + `","outcome":0,"date":"0001-01-01T00:00:00Z","payer":"","description":"","categories":null}]}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().GetFeed(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Transaction{{UserID: uuidTest}}, nil) -// }, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// queryParam: "page=2&page_size=10", -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// // No service calls are expected for unauthorized request. -// }, -// }, -// { -// name: "Invalid Query account", -// user: user, -// queryParam: "account='12'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Invalid Query category", -// user: user, -// queryParam: "category='12'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Invalid Query income", -// user: user, -// queryParam: "income='trueee'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Invalid Query outcome", -// user: user, -// queryParam: "outcome='trueee'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Invalid Query start_date", -// user: user, -// queryParam: "start_date='trueee'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Invalid Query end_date", -// user: user, -// queryParam: "end_date='trueee'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "No Such Transaction Error", -// user: user, -// queryParam: "page=2&page_size=10", -// expectedCode: http.StatusNoContent, -// expectedBody: `{"status":204,"body":""}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// errorNoSuchTransaction := models.NoSuchTransactionError{UserID: uuidTest} -// mockUsecase.EXPECT().GetFeed(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Transaction{}, &errorNoSuchTransaction) -// }, -// }, -// { -// name: "Internal Server Error", -// user: user, -// expectedCode: http.StatusInternalServerError, -// expectedBody: `{"status":500,"message":"can't get feed info"}`, -// mockUsecaseFn: func(mockService *mocks.MockUsecase) { -// internalServerError := errors.New("can't get feed info") -// mockService.EXPECT().GetFeed(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Transaction{}, internalServerError) -// }, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// req := httptest.NewRequest("GET", "/api/user/balance", nil) -// -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// req.URL.RawQuery = tt.queryParam -// } -// -// recorder := httptest.NewRecorder() -// -// mockHandler.GetFeed(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -//} -// -//func TestHandler_GetUserFromRequest(t *testing.T) { -// tests := []struct { -// name string -// user *models.User -// expectedCode int -// expectedBody string -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Unauthorized Request", -// user: nil, -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// req := httptest.NewRequest("GET", "/api/user/balance", nil) -// -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// -// recorder := httptest.NewRecorder() -// -// mockHandler.GetFeed(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -//} -// -//func TestHandler_CreateTransaction(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// -// tests := []struct { -// name string -// user *models.User -// requestBody io.Reader -// expectedCode int -// expectedBody string -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Invalid JSON body", -// user: user, -// requestBody: strings.NewReader("invalid json data"), -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid input body"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// // mockUsecase.EXPECT().CreateTransaction(gomock.Any(), gomock.Any()).Return(uuidTest, nil) -// }, -// }, -// { -// name: "Successful Transaction Creation", -// user: user, -// requestBody: strings.NewReader(`{ -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{"transaction_id":"` + uuidTest.String() + `"}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().CreateTransaction(gomock.Any(), gomock.Any()).Return(uuidTest, nil) -// }, -// }, -// { -// name: "Bad Check valid", -// user: user, -// requestBody: strings.NewReader(`{ -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "payer": "fffffffffffffffffffffffffffffffffffffffffffffffffff", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid input body"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, -// }, -// -// { -// name: "Unauthorized Request", -// user: nil, -// requestBody: strings.NewReader(`{"field1": "value1", "field2": "value2"}`), // Replace with valid JSON -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Transaction Creation Error", -// user: user, -// requestBody: strings.NewReader(`{ -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "income": 0, -// "outcome": 0 -// }`), // Replace with valid JSON -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"can't create transaction"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().CreateTransaction(gomock.Any(), gomock.Any()).Return(uuidTest, errors.New("transaction not created")) -// }, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// req := httptest.NewRequest("POST", "/api/transaction/create", tt.requestBody) -// -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// } -// -// recorder := httptest.NewRecorder() -// -// mockHandler.Create(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -//} -// -//func TestHandler_UpdateTransaction(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// -// tests := []struct { -// name string -// user *models.User -// requestBody io.Reader -// expectedCode int -// expectedBody string -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Successful Transaction Update", -// user: user, -// requestBody: strings.NewReader(`{ -// "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{}}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(nil) -// }, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// requestBody: strings.NewReader(`{"field1": "value1", "field2": "value2"}`), // Replace with valid JSON -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Invalid JSON body", -// user: user, -// requestBody: strings.NewReader("invalid json data"), -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid input body"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// // mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(nil) -// }, -// }, -// { -// name: "Transaction Update Error", -// user: user, -// requestBody: strings.NewReader(`{ -// "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusInternalServerError, -// expectedBody: `{"status":500,"message":"can't get transaction"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(errors.New("transaction not updated")) -// }, -// }, -// { -// name: "Transaction Check valid", -// user: user, -// requestBody: strings.NewReader(`{ -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "payer": "fffffffffffffffffffffffffffffffffffffffffffffffffff", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid input body"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// }, -// { -// name: "Transaction No Such User Error", -// user: user, -// requestBody: strings.NewReader(`{ -// "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"can't such transactoin"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// errorNoSuchTransaction := models.NoSuchTransactionError{UserID: uuidTest} -// mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(&errorNoSuchTransaction) -// }, -// }, -// { -// name: "User Forbidden", -// user: user, -// requestBody: strings.NewReader(`{ -// "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", -// "categories": [], -// "date": "2023-10-02T15:30:00Z", -// "description": "string", -// "income": 0, -// "outcome": 0 -// }`), -// expectedCode: http.StatusForbidden, -// expectedBody: `{"status":403,"message":"user has no rights"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// errorNoSuchUserForbidden := models.ForbiddenUserError{} -// mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(&errorNoSuchUserForbidden) -// }, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// req := httptest.NewRequest("POST", "/api/transaction/update", tt.requestBody) -// -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// } -// -// recorder := httptest.NewRecorder() -// -// mockHandler.Update(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -//} -// -//func TestHandler_TransactionDelete(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest} -// tests := []struct { -// name string -// userID string -// expectedCode int -// flag bool -// expectedBody string -// funcCtxUser func(*models.User, context.Context) context.Context -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Successful call to GetUserBalance", -// userID: uuid.New().String(), -// flag: true, -// expectedCode: http.StatusOK, -// expectedBody: `{"status":200,"body":{}}`, -// -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) -// }, -// funcCtxUser: func(user *models.User, ctx context.Context) context.Context { -// return context.WithValue(ctx, models.ContextKeyUserType{}, user) -// }, -// }, -// { -// name: "Invalid userID", -// userID: "invalidUserID", -// flag: true, -// -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// funcCtxUser: func(user *models.User, ctx context.Context) context.Context { -// return context.WithValue(ctx, models.ContextKeyUserType{}, user) -// }, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// // No expectations for mockUsecase. -// }, -// }, -// { -// name: "Error No Such transaction error", -// userID: uuidTest.String(), -// expectedCode: http.StatusBadRequest, -// flag: true, -// expectedBody: `{"status":400,"message":"can't such transactoin"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// expectedError := models.NoSuchTransactionError{} -// mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(&expectedError) -// }, -// funcCtxUser: func(user *models.User, ctx context.Context) context.Context { -// return context.WithValue(ctx, models.ContextKeyUserType{}, user) -// }, -// }, -// { -// name: "Internal server error", -// userID: uuid.New().String(), -// expectedCode: http.StatusInternalServerError, -// flag: true, -// expectedBody: `{"status":500,"message":"cat't delete transaction"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// //internalErrorUserID := uuid.New() -// internalError := errors.New("internal server error") -// mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(internalError) -// }, -// funcCtxUser: func(user *models.User, ctx context.Context) context.Context { -// return context.WithValue(ctx, models.ContextKeyUserType{}, user) -// }, -// }, -// { -// name: "User Forbidden", -// userID: uuid.New().String(), -// expectedCode: http.StatusForbidden, -// flag: true, -// expectedBody: `{"status":403,"message":"user has no rights"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// //internalErrorUserID := uuid.New() -// errorNoSuchUserForbidden := models.ForbiddenUserError{} -// mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(&errorNoSuchUserForbidden) -// }, -// funcCtxUser: func(user *models.User, ctx context.Context) context.Context { -// return context.WithValue(ctx, models.ContextKeyUserType{}, user) -// }, -// }, -// { -// name: "Unauthorized", -// userID: uuid.New().String(), -// expectedCode: http.StatusUnauthorized, -// flag: false, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// }, -// funcCtxUser: func(user *models.User, ctx context.Context) context.Context { -// return context.WithValue(ctx, models.ContextKeyUserType{}, user) -// }, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// url := "/api/transaction/" + tt.userID + "/delete" -// req := httptest.NewRequest("GET", url, nil) -// req = mux.SetURLVars(req, map[string]string{"transaction_id": tt.userID}) -// -// if tt.flag { -// ctx := tt.funcCtxUser(user, req.Context()) -// -// req = req.WithContext(ctx) -// } -// -// recorder := httptest.NewRecorder() -// mockHandler.Delete(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// -// assert.Equal(t, tt.expectedCode, recorder.Code) -// assert.Equal(t, tt.expectedBody, actual) -// }) -// } -//} -// -//func TestHandler_ExportTransactions(t *testing.T) { -// uuidTest := uuid.New() -// user := &models.User{ID: uuidTest, Login: "testuser"} -// // nilUUID := uuid.Nil -// -// tests := []struct { -// name string -// user *models.User -// query string -// expectedCode int -// expectedBody string -// mockUsecaseFn func(*mocks.MockUsecase) -// }{ -// { -// name: "Successful call to GetTransactionForExport", -// user: user, -// query: "page=2&page_size=10", -// expectedCode: http.StatusOK, -// expectedBody: "\r\nContent-Disposition: form-data; name=\"file\"; filename=\"dataFeed.csv\"\r\nContent-Type: application/octet-stream\r\n\r\nAccountIncome,AccountOutcome,Income,Outcome,Date,Payer,Description,Categories\n,,0.000000,0.000000,0001-01-01T00:00:00Z,,\n\r\n", -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// mockUsecase.EXPECT().GetTransactionForExport(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.TransactionExport{{ID: uuidTest}}, nil) -// }, -// }, -// { -// name: "Unauthorized Request", -// user: nil, -// query: "page=2&page_size=10", -// expectedCode: http.StatusUnauthorized, -// expectedBody: `{"status":401,"message":"unauthorized"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, -// }, -// { -// name: "Invalid Query start_date", -// user: user, -// query: "start_date='trueee'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, -// }, -// { -// name: "Invalid Query end_date", -// user: user, -// query: "end_date='trueee'", -// expectedCode: http.StatusBadRequest, -// expectedBody: `{"status":400,"message":"invalid url parameter"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, -// }, -// { -// name: "No Such Transaction Error", -// user: user, -// query: "page=2&page_size=10", -// expectedCode: http.StatusNotFound, -// expectedBody: `{"status":404,"message":"no transactions found"}`, -// mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { -// errorNoSuchTransaction := models.NoSuchTransactionError{UserID: uuidTest} -// mockUsecase.EXPECT().GetTransactionForExport(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.TransactionExport{}, &errorNoSuchTransaction) -// }, -// }, -// { -// name: "Internal Server Error", -// user: user, -// expectedCode: http.StatusInternalServerError, -// expectedBody: `{"status":500,"message":"can't get feed info"}`, -// mockUsecaseFn: func(mockService *mocks.MockUsecase) { -// internalServerError := errors.New("can't get feed info") -// mockService.EXPECT().GetTransactionForExport(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.TransactionExport{}, internalServerError) -// }, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctrl := gomock.NewController(t) -// defer ctrl.Finish() -// -// mockService := mocks.NewMockUsecase(ctrl) -// tt.mockUsecaseFn(mockService) -// -// mockUsecase := mockUser.NewMockUsecase(ctrl) -// mockAccount := mockClient.NewMockAccountServiceClient(ctrl) -// -// mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) -// -// // Set up the request -// url := "/api/export/transactions" -// req := httptest.NewRequest("GET", url, nil) -// if tt.user != nil { -// ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) -// req = req.WithContext(ctx) -// req.URL.RawQuery = tt.query -// } -// -// recorder := httptest.NewRecorder() -// -// mockHandler.ExportTransactions(recorder, req) -// -// actual := strings.TrimSpace(recorder.Body.String()) -// assert.Equal(t, tt.expectedCode, recorder.Code) -// if tt.name == "Successful call to GetTransactionForExport" { -// assert.Equal(t, true, strings.Contains(actual, tt.expectedBody)) -// // fmt.Println("expected >>>> ", tt.expectedBody) -// // fmt.Println("actual >>>> ", actual) -// } else { -// assert.Equal(t, tt.expectedBody, actual) -// } -// }) -// } -//} +import ( + "context" + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/go-park-mail-ru/2023_2_Hamster/internal/common/logger" + mockClient "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/account/mocks" + mocks "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/transaction/mocks" + mockUser "github.com/go-park-mail-ru/2023_2_Hamster/internal/microservices/user/mocks" + "github.com/go-park-mail-ru/2023_2_Hamster/internal/models" + "github.com/golang/mock/gomock" + "github.com/google/uuid" + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" +) + +func TestHandler_GetCount(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tests := []struct { + name string + user *models.User + expectedCode int + expectedBody string + mockUsecaseFn func(*mocks.MockUsecase) + }{ + { + name: "Successful call to Get count", + user: user, + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{"count":1}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().GetCount(gomock.Any(), gomock.Any()).Return(1, nil) + }, + }, + { + name: "Unauthorized Request", + user: nil, + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + // No service calls are expected for unauthorized request. + }, + }, + { + name: "Internal request Error", + user: user, + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"can't get count transaction info"}`, + mockUsecaseFn: func(mockService *mocks.MockUsecase) { + internalServerError := errors.New("can't get feed info") + mockService.EXPECT().GetCount(gomock.Any(), gomock.Any()).Return(1, internalServerError) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("GET", "/api/user/balance", nil) + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.GetCount(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_GetFeed(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tests := []struct { + name string + user *models.User + queryParam string + expectedCode int + expectedBody string + mockUsecaseFn func(*mocks.MockUsecase) + mockUserFn func(*mockUser.MockUsecase) + }{ + { + name: "Successful call to GetFeed", + user: user, + queryParam: "page=2&page_size=10", + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{"transactions":[{"id":"00000000-0000-0000-0000-000000000000","account_income":"00000000-0000-0000-0000-000000000000","account_outcome":"00000000-0000-0000-0000-000000000000","income":0,"login":"login","outcome":0,"date":"0001-01-01T00:00:00Z","payer":"","description":"","categories":null}]}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().GetFeed(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Transaction{{UserID: uuidTest}}, nil) + }, + mockUserFn: func(mu *mockUser.MockUsecase) { + mu.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(&models.User{ID: uuidTest, Login: "login", Username: "username"}, nil) + }, + }, + { + name: "Unauthorized Request", + user: nil, + queryParam: "page=2&page_size=10", + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Invalid Query account", + user: user, + queryParam: "account='12'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Invalid Query category", + user: user, + queryParam: "category='12'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Invalid Query income", + user: user, + queryParam: "income='trueee'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Invalid Query outcome", + user: user, + queryParam: "outcome='trueee'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Invalid Query start_date", + user: user, + queryParam: "start_date='trueee'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Invalid Query end_date", + user: user, + queryParam: "end_date='trueee'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "No Such Transaction Error", + user: user, + queryParam: "page=2&page_size=10", + expectedCode: http.StatusNoContent, + expectedBody: `{"status":204,"body":{}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + errorNoSuchTransaction := models.NoSuchTransactionError{UserID: uuidTest} + mockUsecase.EXPECT().GetFeed(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Transaction{}, &errorNoSuchTransaction) + }, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + { + name: "Internal Server Error", + user: user, + expectedCode: http.StatusInternalServerError, + expectedBody: `{"status":500,"message":"can't get feed info"}`, + mockUsecaseFn: func(mockService *mocks.MockUsecase) { + internalServerError := errors.New("can't get feed info") + mockService.EXPECT().GetFeed(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.Transaction{}, internalServerError) + }, + mockUserFn: func(mu *mockUser.MockUsecase) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + tt.mockUserFn(mockUsecase) + + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("GET", "/api/user/balance", nil) + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + req.URL.RawQuery = tt.queryParam + } + + recorder := httptest.NewRecorder() + + mockHandler.GetFeed(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_GetUserFromRequest(t *testing.T) { + tests := []struct { + name string + user *models.User + expectedCode int + expectedBody string + mockUsecaseFn func(*mocks.MockUsecase) + }{ + { + name: "Unauthorized Request", + user: nil, + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("GET", "/api/user/balance", nil) + + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + + recorder := httptest.NewRecorder() + + mockHandler.GetFeed(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_CreateTransaction(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + + tests := []struct { + name string + user *models.User + requestBody io.Reader + expectedCode int + expectedBody string + mockUsecaseFn func(*mocks.MockUsecase) + }{ + { + name: "Invalid JSON body", + user: user, + requestBody: strings.NewReader("invalid json data"), + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid input body"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + // mockUsecase.EXPECT().CreateTransaction(gomock.Any(), gomock.Any()).Return(uuidTest, nil) + }, + }, + { + name: "Successful Transaction Creation", + user: user, + requestBody: strings.NewReader(`{ + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{"transaction_id":"` + uuidTest.String() + `"}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().CreateTransaction(gomock.Any(), gomock.Any()).Return(uuidTest, nil) + }, + }, + { + name: "Bad Check valid", + user: user, + requestBody: strings.NewReader(`{ + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "payer": "fffffffffffffffffffffffffffffffffffffffffffffffffff", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid input body"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + }, + + { + name: "Unauthorized Request", + user: nil, + requestBody: strings.NewReader(`{"field1": "value1", "field2": "value2"}`), // Replace with valid JSON + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + }, + }, + { + name: "Transaction Creation Error", + user: user, + requestBody: strings.NewReader(`{ + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "income": 0, + "outcome": 0 + }`), // Replace with valid JSON + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"can't create transaction"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().CreateTransaction(gomock.Any(), gomock.Any()).Return(uuidTest, errors.New("transaction not created")) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("POST", "/api/transaction/create", tt.requestBody) + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.Create(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_UpdateTransaction(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + + tests := []struct { + name string + user *models.User + requestBody io.Reader + expectedCode int + expectedBody string + mockUsecaseFn func(*mocks.MockUsecase) + }{ + { + name: "Successful Transaction Update", + user: user, + requestBody: strings.NewReader(`{ + "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{}}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(nil) + }, + }, + { + name: "Unauthorized Request", + user: nil, + requestBody: strings.NewReader(`{"field1": "value1", "field2": "value2"}`), // Replace with valid JSON + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + }, + }, + { + name: "Invalid JSON body", + user: user, + requestBody: strings.NewReader("invalid json data"), + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid input body"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + // mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(nil) + }, + }, + { + name: "Transaction Update Error", + user: user, + requestBody: strings.NewReader(`{ + "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusInternalServerError, + expectedBody: `{"status":500,"message":"can't get transaction"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(errors.New("transaction not updated")) + }, + }, + { + name: "Transaction Check valid", + user: user, + requestBody: strings.NewReader(`{ + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "payer": "fffffffffffffffffffffffffffffffffffffffffffffffffff", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid input body"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + }, + }, + { + name: "Transaction No Such User Error", + user: user, + requestBody: strings.NewReader(`{ + "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"can't such transactoin"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + errorNoSuchTransaction := models.NoSuchTransactionError{UserID: uuidTest} + mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(&errorNoSuchTransaction) + }, + }, + { + name: "User Forbidden", + user: user, + requestBody: strings.NewReader(`{ + "transaction_id": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_income": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "account_outcome": "7c62a6ef-2c4c-48c1-8a98-825fb6a3f0e6", + "categories": [], + "date": "2023-10-02T15:30:00Z", + "description": "string", + "income": 0, + "outcome": 0 + }`), + expectedCode: http.StatusForbidden, + expectedBody: `{"status":403,"message":"user has no rights"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + errorNoSuchUserForbidden := models.ForbiddenUserError{} + mockUsecase.EXPECT().UpdateTransaction(gomock.Any(), gomock.Any()).Return(&errorNoSuchUserForbidden) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + req := httptest.NewRequest("POST", "/api/transaction/update", tt.requestBody) + + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + + mockHandler.Update(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_TransactionDelete(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest} + tests := []struct { + name string + userID string + expectedCode int + flag bool + expectedBody string + funcCtxUser func(*models.User, context.Context) context.Context + mockUsecaseFn func(*mocks.MockUsecase) + }{ + { + name: "Successful call to GetUserBalance", + userID: uuid.New().String(), + flag: true, + expectedCode: http.StatusOK, + expectedBody: `{"status":200,"body":{}}`, + + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + }, + funcCtxUser: func(user *models.User, ctx context.Context) context.Context { + return context.WithValue(ctx, models.ContextKeyUserType{}, user) + }, + }, + { + name: "Invalid userID", + userID: "invalidUserID", + flag: true, + + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + funcCtxUser: func(user *models.User, ctx context.Context) context.Context { + return context.WithValue(ctx, models.ContextKeyUserType{}, user) + }, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + // No expectations for mockUsecase. + }, + }, + { + name: "Error No Such transaction error", + userID: uuidTest.String(), + expectedCode: http.StatusBadRequest, + flag: true, + expectedBody: `{"status":400,"message":"can't such transactoin"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + expectedError := models.NoSuchTransactionError{} + mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(&expectedError) + }, + funcCtxUser: func(user *models.User, ctx context.Context) context.Context { + return context.WithValue(ctx, models.ContextKeyUserType{}, user) + }, + }, + { + name: "Internal server error", + userID: uuid.New().String(), + expectedCode: http.StatusInternalServerError, + flag: true, + expectedBody: `{"status":500,"message":"cat't delete transaction"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + //internalErrorUserID := uuid.New() + internalError := errors.New("internal server error") + mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(internalError) + }, + funcCtxUser: func(user *models.User, ctx context.Context) context.Context { + return context.WithValue(ctx, models.ContextKeyUserType{}, user) + }, + }, + { + name: "User Forbidden", + userID: uuid.New().String(), + expectedCode: http.StatusForbidden, + flag: true, + expectedBody: `{"status":403,"message":"user has no rights"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + //internalErrorUserID := uuid.New() + errorNoSuchUserForbidden := models.ForbiddenUserError{} + mockUsecase.EXPECT().DeleteTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(&errorNoSuchUserForbidden) + }, + funcCtxUser: func(user *models.User, ctx context.Context) context.Context { + return context.WithValue(ctx, models.ContextKeyUserType{}, user) + }, + }, + { + name: "Unauthorized", + userID: uuid.New().String(), + expectedCode: http.StatusUnauthorized, + flag: false, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + }, + funcCtxUser: func(user *models.User, ctx context.Context) context.Context { + return context.WithValue(ctx, models.ContextKeyUserType{}, user) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + url := "/api/transaction/" + tt.userID + "/delete" + req := httptest.NewRequest("GET", url, nil) + req = mux.SetURLVars(req, map[string]string{"transaction_id": tt.userID}) + + if tt.flag { + ctx := tt.funcCtxUser(user, req.Context()) + + req = req.WithContext(ctx) + } + + recorder := httptest.NewRecorder() + mockHandler.Delete(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + + assert.Equal(t, tt.expectedCode, recorder.Code) + assert.Equal(t, tt.expectedBody, actual) + }) + } +} + +func TestHandler_ExportTransactions(t *testing.T) { + uuidTest := uuid.New() + user := &models.User{ID: uuidTest, Login: "testuser"} + // nilUUID := uuid.Nil + + tests := []struct { + name string + user *models.User + query string + expectedCode int + expectedBody string + mockUsecaseFn func(*mocks.MockUsecase) + }{ + { + name: "Successful call to GetTransactionForExport", + user: user, + query: "page=2&page_size=10", + expectedCode: http.StatusOK, + expectedBody: "\r\nContent-Disposition: form-data; name=\"file\"; filename=\"dataFeed.csv\"\r\nContent-Type: application/octet-stream\r\n\r\nAccountIncome,AccountOutcome,Income,Outcome,Date,Payer,Description,Categories\n,,0.000000,0.000000,0001-01-01T00:00:00Z,,\n\r\n", + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + mockUsecase.EXPECT().GetTransactionForExport(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.TransactionExport{{ID: uuidTest}}, nil) + }, + }, + { + name: "Unauthorized Request", + user: nil, + query: "page=2&page_size=10", + expectedCode: http.StatusUnauthorized, + expectedBody: `{"status":401,"message":"unauthorized"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + }, + { + name: "Invalid Query start_date", + user: user, + query: "start_date='trueee'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + }, + { + name: "Invalid Query end_date", + user: user, + query: "end_date='trueee'", + expectedCode: http.StatusBadRequest, + expectedBody: `{"status":400,"message":"invalid url parameter"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) {}, + }, + { + name: "No Such Transaction Error", + user: user, + query: "page=2&page_size=10", + expectedCode: http.StatusNotFound, + expectedBody: `{"status":404,"message":"no transactions found"}`, + mockUsecaseFn: func(mockUsecase *mocks.MockUsecase) { + errorNoSuchTransaction := models.NoSuchTransactionError{UserID: uuidTest} + mockUsecase.EXPECT().GetTransactionForExport(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.TransactionExport{}, &errorNoSuchTransaction) + }, + }, + { + name: "Internal Server Error", + user: user, + expectedCode: http.StatusInternalServerError, + expectedBody: `{"status":500,"message":"can't get feed info"}`, + mockUsecaseFn: func(mockService *mocks.MockUsecase) { + internalServerError := errors.New("can't get feed info") + mockService.EXPECT().GetTransactionForExport(gomock.Any(), gomock.Any(), gomock.Any()).Return([]models.TransactionExport{}, internalServerError) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockService := mocks.NewMockUsecase(ctrl) + tt.mockUsecaseFn(mockService) + + mockUsecase := mockUser.NewMockUsecase(ctrl) + mockAccount := mockClient.NewMockAccountServiceClient(ctrl) + + mockHandler := NewHandler(mockService, mockUsecase, mockAccount, *logger.NewLogger(context.TODO())) + + // Set up the request + url := "/api/export/transactions" + req := httptest.NewRequest("GET", url, nil) + if tt.user != nil { + ctx := context.WithValue(req.Context(), models.ContextKeyUserType{}, tt.user) + req = req.WithContext(ctx) + req.URL.RawQuery = tt.query + } + + recorder := httptest.NewRecorder() + + mockHandler.ExportTransactions(recorder, req) + + actual := strings.TrimSpace(recorder.Body.String()) + assert.Equal(t, tt.expectedCode, recorder.Code) + if tt.name == "Successful call to GetTransactionForExport" { + assert.Equal(t, true, strings.Contains(actual, tt.expectedBody)) + // fmt.Println("expected >>>> ", tt.expectedBody) + // fmt.Println("actual >>>> ", actual) + } else { + assert.Equal(t, tt.expectedBody, actual) + } + }) + } +} diff --git a/internal/microservices/transaction/repository/postgresql/postgres_test.go b/internal/microservices/transaction/repository/postgresql/postgres_test.go index b010ac2..b5056a3 100644 --- a/internal/microservices/transaction/repository/postgresql/postgres_test.go +++ b/internal/microservices/transaction/repository/postgresql/postgres_test.go @@ -8,7 +8,6 @@ import ( "reflect" "regexp" "testing" - "time" "github.com/go-park-mail-ru/2023_2_Hamster/internal/common/logger" "github.com/go-park-mail-ru/2023_2_Hamster/internal/models" @@ -85,213 +84,213 @@ func TestGetCount(t *testing.T) { } } -func TestGetFeed(t *testing.T) { - userID := uuid.New() - transactionID1 := uuid.New() - categoryID := uuid.New() - time := time.Now() - categories := []models.CategoryName{{ID: categoryID, Name: "ffdsf"}} - tests := []struct { - name string - rows *pgxmock.Rows - rowsCategory *pgxmock.Rows - rowsCategoryErr error - err error - rowsErr error - expected []models.Transaction - expectedLast bool - errTransaction bool - }{ - { - name: "ValidFeed", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - categoryID, - "ffdsf", - ), - - err: nil, - rowsErr: nil, - rowsCategoryErr: nil, - expected: []models.Transaction{{ID: transactionID1, UserID: userID, AccountIncomeID: transactionID1, AccountOutcomeID: transactionID1, Income: 100.0, Outcome: 0.0, Date: time, Payer: "John Doe", Description: "Transaction 1", Categories: categories}}, - expectedLast: false, - errTransaction: true, - }, - { - name: "Invalid Scan Category", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - "dff", - "sfd", - ), - - err: fmt.Errorf("[repo] Scanning value error for column 'category_id': Scan: invalid UUID length: 3"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: true, - }, - { - name: "Invalid Scan transaction", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - "fff", userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - - err: fmt.Errorf("[repo] Scanning value error for column 'id': Scan: invalid UUID length: 3"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: false, - }, - { - name: "INValid category", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - categoryID, - "dddd", - ), - - err: fmt.Errorf("[repo] err"), - rowsErr: nil, - rowsCategoryErr: errors.New("err"), - expected: nil, - expectedLast: false, - errTransaction: true, - }, - { - name: "Rows err", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).RowError(0, errors.New("err")), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }), - - err: fmt.Errorf("[repo] err"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: false, - }, - { - name: "Rows err", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).RowError(0, errors.New("err")), - err: fmt.Errorf("[repo] err"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: true, - }, - { - name: "NoRows", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }), - rowsErr: nil, - rowsCategoryErr: nil, - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }), - err: fmt.Errorf("[repo] %w: ", &models.NoSuchTransactionError{UserID: userID}), - expected: nil, - expectedLast: false, - errTransaction: false, - }, - { - name: "DatabaseError", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }), - rowsErr: errors.New("err"), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - uuid.New(), - "ffff", - ), - rowsCategoryErr: errors.New("err"), - err: fmt.Errorf("[repo] err"), - expected: nil, - expectedLast: false, - errTransaction: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - mock, _ := pgxmock.NewPool() - ctl := gomock.NewController(t) - defer ctl.Finish() - logger := *logger.NewLogger(context.TODO()) - repo := NewRepository(mock, logger) - - escapedQuery := regexp.QuoteMeta(transactionGetFeed + " ORDER BY date DESC;") - mock.ExpectQuery(escapedQuery). - WithArgs(userID.String()). - WillReturnRows(test.rows). - WillReturnError(test.rowsErr) - - if test.errTransaction { - escapedQueryCategory := regexp.QuoteMeta(transactionGetCategory) - mock.ExpectQuery(escapedQueryCategory). - WithArgs(transactionID1). - WillReturnRows(test.rowsCategory). - WillReturnError(test.rowsCategoryErr) - } - transactions, err := repo.GetFeed(context.Background(), userID, &models.QueryListOptions{}) - - if !reflect.DeepEqual(transactions, test.expected) { - t.Errorf("Expected transactions: %v, but got: %v", test.expected, transactions) - } - - if (test.err == nil && err != nil) || (test.err != nil && err == nil) || (test.err != nil && err != nil && test.err.Error() != err.Error()) { - t.Errorf("Expected error: %v, but got: %v", test.err, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("There were unfulfilled expectations: %s", err) - } - }) - } -} +// func TestGetFeed(t *testing.T) { +// userID := uuid.New() +// transactionID1 := uuid.New() +// categoryID := uuid.New() +// time := time.Now() +// categories := []models.CategoryName{{ID: categoryID, Name: "ffdsf"}} +// tests := []struct { +// name string +// rows *pgxmock.Rows +// rowsCategory *pgxmock.Rows +// rowsCategoryErr error +// err error +// rowsErr error +// expected []models.Transaction +// expectedLast bool +// errTransaction bool +// }{ +// { +// name: "ValidFeed", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// categoryID, +// "ffdsf", +// ), + +// err: nil, +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: []models.Transaction{{ID: transactionID1, UserID: userID, AccountIncomeID: transactionID1, AccountOutcomeID: transactionID1, Income: 100.0, Outcome: 0.0, Date: time, Payer: "John Doe", Description: "Transaction 1", Categories: categories}}, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "Invalid Scan Category", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// "dff", +// "sfd", +// ), + +// err: fmt.Errorf("[repo] Scanning value error for column 'category_id': Scan: invalid UUID length: 3"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "Invalid Scan transaction", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// "fff", userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), + +// err: fmt.Errorf("[repo] Scanning value error for column 'id': Scan: invalid UUID length: 3"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// { +// name: "INValid category", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// categoryID, +// "dddd", +// ), + +// err: fmt.Errorf("[repo] err"), +// rowsErr: nil, +// rowsCategoryErr: errors.New("err"), +// expected: nil, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "Rows err", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).RowError(0, errors.New("err")), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }), + +// err: fmt.Errorf("[repo] err"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// { +// name: "Rows err", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).RowError(0, errors.New("err")), +// err: fmt.Errorf("[repo] err"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "NoRows", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }), +// rowsErr: nil, +// rowsCategoryErr: nil, +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }), +// err: fmt.Errorf("[repo] %w: ", &models.NoSuchTransactionError{UserID: userID}), +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// { +// name: "DatabaseError", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }), +// rowsErr: errors.New("err"), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// uuid.New(), +// "ffff", +// ), +// rowsCategoryErr: errors.New("err"), +// err: fmt.Errorf("[repo] err"), +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// } + +// for _, test := range tests { +// t.Run(test.name, func(t *testing.T) { +// mock, _ := pgxmock.NewPool() +// ctl := gomock.NewController(t) +// defer ctl.Finish() +// logger := *logger.NewLogger(context.TODO()) +// repo := NewRepository(mock, logger) + +// escapedQuery := regexp.QuoteMeta(transactionGetFeed + " ORDER BY date DESC;") +// mock.ExpectQuery(escapedQuery). +// WithArgs(userID.String()). +// WillReturnRows(test.rows). +// WillReturnError(test.rowsErr) + +// if test.errTransaction { +// escapedQueryCategory := regexp.QuoteMeta(transactionGetCategory) +// mock.ExpectQuery(escapedQueryCategory). +// WithArgs(transactionID1). +// WillReturnRows(test.rowsCategory). +// WillReturnError(test.rowsCategoryErr) +// } +// transactions, err := repo.GetFeed(context.Background(), userID, &models.QueryListOptions{}) + +// if !reflect.DeepEqual(transactions, test.expected) { +// t.Errorf("Expected transactions: %v, but got: %v", test.expected, transactions) +// } + +// if (test.err == nil && err != nil) || (test.err != nil && err == nil) || (test.err != nil && err != nil && test.err.Error() != err.Error()) { +// t.Errorf("Expected error: %v, but got: %v", test.err, err) +// } + +// if err := mock.ExpectationsWereMet(); err != nil { +// t.Errorf("There were unfulfilled expectations: %s", err) +// } +// }) +// } +// } func TestInsertTransaction(t *testing.T) { transactionID := uuid.New() @@ -740,212 +739,211 @@ func TestCheckForbidden(t *testing.T) { } } -/* -func TestGetExportInfo(t *testing.T) { - userID := uuid.New() - transactionID1 := uuid.New() - categoryID := uuid.New() - time := time.Now() - categories := []models.CategoryName{{ID: categoryID, Name: "ffdsf"}} - tests := []struct { - name string - rows *pgxmock.Rows - rowsCategory *pgxmock.Rows - rowsCategoryErr error - err error - rowsErr error - expected []models.Transaction - expectedLast bool - errTransaction bool - }{ - { - name: "ValidFeed", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - categoryID, - "ffdsf", - ), - - err: nil, - rowsErr: nil, - rowsCategoryErr: nil, - expected: []models.Transaction{{ID: transactionID1, UserID: userID, AccountIncomeID: transactionID1, AccountOutcomeID: transactionID1, Income: 100.0, Outcome: 0.0, Date: time, Payer: "John Doe", Description: "Transaction 1", Categories: categories}}, - expectedLast: false, - errTransaction: true, - }, - { - name: "Invalid Scan Category", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - "dff", - "sfd", - ), - - err: fmt.Errorf("[repo] Scanning value error for column 'category_id': Scan: invalid UUID length: 3"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: true, - }, - { - name: "Invalid Scan transaction", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - "fff", userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - - err: fmt.Errorf("[repo] Scanning value error for column 'id': Scan: invalid UUID length: 3"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: false, - }, - { - name: "INValid category", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - categoryID, - "dddd", - ), - - err: fmt.Errorf("[repo] err"), - rowsErr: nil, - rowsCategoryErr: errors.New("err"), - expected: nil, - expectedLast: false, - errTransaction: true, - }, - { - name: "Rows err", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).RowError(0, errors.New("err")), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }), - - err: fmt.Errorf("[repo] err"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: false, - }, - { - name: "Rows err", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }).AddRow( - transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", - ), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).RowError(0, errors.New("err")), - err: fmt.Errorf("[repo] err"), - rowsErr: nil, - rowsCategoryErr: nil, - expected: nil, - expectedLast: false, - errTransaction: true, - }, - { - name: "NoRows", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }), - rowsErr: nil, - rowsCategoryErr: nil, - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }), - err: fmt.Errorf("[repo] %w: ", &models.NoSuchTransactionError{UserID: userID}), - expected: nil, - expectedLast: false, - errTransaction: false, - }, - { - name: "DatabaseError", - rows: pgxmock.NewRows([]string{ - "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", - }), - rowsErr: errors.New("err"), - rowsCategory: pgxmock.NewRows([]string{ - "category_id", - "name", - }).AddRow( - uuid.New(), - "ffff", - ), - rowsCategoryErr: errors.New("err"), - err: fmt.Errorf("[repo] err"), - expected: nil, - expectedLast: false, - errTransaction: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - mock, _ := pgxmock.NewPool() - ctl := gomock.NewController(t) - defer ctl.Finish() - logger := *logger.NewLogger(context.TODO()) - repo := NewRepository(mock, logger) - - escapedQuery := regexp.QuoteMeta(transactionGetFeed + " ORDER BY date DESC;") - mock.ExpectQuery(escapedQuery). - WithArgs(userID.String()). - WillReturnRows(test.rows). - WillReturnError(test.rowsErr) - - if test.errTransaction { - escapedQueryCategory := regexp.QuoteMeta(transactionGetFeedForExport) - mock.ExpectQuery(escapedQueryCategory). - WithArgs(transactionID1). - WillReturnRows(test.rowsCategory). - WillReturnError(test.rowsCategoryErr) - } - transactions, err := repo.GetTransactionForExport(context.Background(), userID, &models.QueryListOptions{}) - - if !reflect.DeepEqual(transactions, test.expected) { - t.Errorf("Expected transactions: %v, but got: %v", test.expected, transactions) - } - - if (test.err == nil && err != nil) || (test.err != nil && err == nil) || (test.err != nil && err != nil && test.err.Error() != err.Error()) { - t.Errorf("Expected error: %v, but got: %v", test.err, err) - } - - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("There were unfulfilled expectations: %s", err) - } - }) - } -} -*/ +// func TestGetExportInfo(t *testing.T) { +// userID := uuid.New() +// transactionID1 := uuid.New() +// categoryID := uuid.New() +// time := time.Now() +// categories := []models.CategoryName{{ID: categoryID, Name: "ffdsf"}} +// tests := []struct { +// name string +// rows *pgxmock.Rows +// rowsCategory *pgxmock.Rows +// rowsCategoryErr error +// err error +// rowsErr error +// expected []models.Transaction +// expectedLast bool +// errTransaction bool +// }{ +// { +// name: "ValidFeed", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// categoryID, +// "ffdsf", +// ), + +// err: nil, +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: []models.Transaction{{ID: transactionID1, UserID: userID, AccountIncomeID: transactionID1, AccountOutcomeID: transactionID1, Income: 100.0, Outcome: 0.0, Date: time, Payer: "John Doe", Description: "Transaction 1", Categories: categories}}, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "Invalid Scan Category", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// "dff", +// "sfd", +// ), + +// err: fmt.Errorf("[repo] Scanning value error for column 'category_id': Scan: invalid UUID length: 3"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "Invalid Scan transaction", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// "fff", userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), + +// err: fmt.Errorf("[repo] Scanning value error for column 'id': Scan: invalid UUID length: 3"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// { +// name: "INValid category", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// categoryID, +// "dddd", +// ), + +// err: fmt.Errorf("[repo] err"), +// rowsErr: nil, +// rowsCategoryErr: errors.New("err"), +// expected: nil, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "Rows err", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).RowError(0, errors.New("err")), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }), + +// err: fmt.Errorf("[repo] err"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// { +// name: "Rows err", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }).AddRow( +// transactionID1, userID, transactionID1, transactionID1, 100.0, 0.0, time, "John Doe", "Transaction 1", +// ), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).RowError(0, errors.New("err")), +// err: fmt.Errorf("[repo] err"), +// rowsErr: nil, +// rowsCategoryErr: nil, +// expected: nil, +// expectedLast: false, +// errTransaction: true, +// }, +// { +// name: "NoRows", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }), +// rowsErr: nil, +// rowsCategoryErr: nil, +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }), +// err: fmt.Errorf("[repo] %w: ", &models.NoSuchTransactionError{UserID: userID}), +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// { +// name: "DatabaseError", +// rows: pgxmock.NewRows([]string{ +// "id", "user_id", "account_income_id", "account_outcome_id", "income", "outcome", "date", "payer", "description", +// }), +// rowsErr: errors.New("err"), +// rowsCategory: pgxmock.NewRows([]string{ +// "category_id", +// "name", +// }).AddRow( +// uuid.New(), +// "ffff", +// ), +// rowsCategoryErr: errors.New("err"), +// err: fmt.Errorf("[repo] err"), +// expected: nil, +// expectedLast: false, +// errTransaction: false, +// }, +// } + +// for _, test := range tests { +// t.Run(test.name, func(t *testing.T) { +// mock, _ := pgxmock.NewPool() +// ctl := gomock.NewController(t) +// defer ctl.Finish() + +// logger := *logger.NewLogger(context.TODO()) +// repo := NewRepository(mock, logger) + +// escapedQuery := regexp.QuoteMeta(transactionGetFeedForExport + " ORDER BY date DESC;") +// mock.ExpectQuery(escapedQuery). +// WithArgs(userID.String()). +// WillReturnRows(test.rows). +// WillReturnError(test.rowsErr) + +// if test.errTransaction { +// escapedQueryCategory := regexp.QuoteMeta(transactionGetFeedForExport) +// mock.ExpectQuery(escapedQueryCategory). +// WithArgs(transactionID1). +// WillReturnRows(test.rowsCategory). +// WillReturnError(test.rowsCategoryErr) +// } +// transactions, err := repo.GetTransactionForExport(context.Background(), userID, &models.QueryListOptions{}) + +// if !reflect.DeepEqual(transactions, test.expected) { +// t.Errorf("Expected transactions: %v, but got: %v", test.expected, transactions) +// } + +// if (test.err == nil && err != nil) || (test.err != nil && err == nil) || (test.err != nil && err != nil && test.err.Error() != err.Error()) { +// t.Errorf("Expected error: %v, but got: %v", test.err, err) +// } + +// if err := mock.ExpectationsWereMet(); err != nil { +// t.Errorf("There were unfulfilled expectations: %s", err) +// } +// }) +// } +// } diff --git a/internal/microservices/user/mocks/user_mock.go b/internal/microservices/user/mocks/user_mock.go index bcae8a1..a12a1de 100644 --- a/internal/microservices/user/mocks/user_mock.go +++ b/internal/microservices/user/mocks/user_mock.go @@ -125,6 +125,21 @@ func (mr *MockUsecaseMockRecorder) GetPlannedBudget(ctx, userID interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlannedBudget", reflect.TypeOf((*MockUsecase)(nil).GetPlannedBudget), ctx, userID) } +// GetUser mocks base method. +func (m *MockUsecase) GetUser(ctx context.Context, userID uuid.UUID) (*models.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUser", ctx, userID) + ret0, _ := ret[0].(*models.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUser indicates an expected call of GetUser. +func (mr *MockUsecaseMockRecorder) GetUser(ctx, userID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockUsecase)(nil).GetUser), ctx, userID) +} + // GetUserBalance mocks base method. func (m *MockUsecase) GetUserBalance(ctx context.Context, userID uuid.UUID) (float64, error) { m.ctrl.T.Helper()