From a491166330395e564d7e93b24aec22f89f0e97a6 Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Tue, 16 Jun 2026 10:13:04 +0300 Subject: [PATCH 1/7] init --- Makefile | 4 + internal/api/dashboards/v1/grpc/api.go | 6 +- internal/api/dashboards/v1/http/api.go | 6 +- .../api/dashboards/v1/http/create_test.go | 61 +++----- internal/api/dashboards/v1/http/test_data.go | 5 + .../pkg/service/dashboards/mock/service.go | 145 ++++++++++++++++++ .../{dashboards.go => dashboards/service.go} | 39 +++-- internal/pkg/service/service.go | 8 - 8 files changed, 203 insertions(+), 71 deletions(-) create mode 100644 internal/pkg/service/dashboards/mock/service.go rename internal/pkg/service/{dashboards.go => dashboards/service.go} (67%) diff --git a/Makefile b/Makefile index af5143d..d9dda90 100644 --- a/Makefile +++ b/Makefile @@ -122,6 +122,10 @@ mock: -destination=internal/app/auth/mock/auth.go \ github.com/ozontech/seq-ui/internal/app/auth \ OIDCProvider,JWTProvider + PATH="$(LOCAL_BIN):$(PATH)" mockgen \ + -destination=internal/pkg/service/dashboards/mock/service.go \ + github.com/ozontech/seq-ui/internal/pkg/service/dashboards \ + Service .PHONY: protoc protoc: diff --git a/internal/api/dashboards/v1/grpc/api.go b/internal/api/dashboards/v1/grpc/api.go index 7e59b4e..dfc6457 100644 --- a/internal/api/dashboards/v1/grpc/api.go +++ b/internal/api/dashboards/v1/grpc/api.go @@ -2,18 +2,18 @@ package grpc import ( "github.com/ozontech/seq-ui/internal/api/profiles" - "github.com/ozontech/seq-ui/internal/pkg/service" + dashboardsservice "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" "github.com/ozontech/seq-ui/pkg/dashboards/v1" ) type API struct { dashboards.UnimplementedDashboardsServiceServer - service service.Service + service dashboardsservice.Service profiles *profiles.Profiles } -func New(svc service.Service, p *profiles.Profiles) *API { +func New(svc dashboardsservice.Service, p *profiles.Profiles) *API { return &API{ service: svc, profiles: p, diff --git a/internal/api/dashboards/v1/http/api.go b/internal/api/dashboards/v1/http/api.go index b192e69..02e67f2 100644 --- a/internal/api/dashboards/v1/http/api.go +++ b/internal/api/dashboards/v1/http/api.go @@ -5,15 +5,15 @@ import ( "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/app/types" - "github.com/ozontech/seq-ui/internal/pkg/service" + dashboardsservice "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" ) type API struct { - service service.Service + service dashboardsservice.Service profiles *profiles.Profiles } -func New(svc service.Service, p *profiles.Profiles) *API { +func New(svc dashboardsservice.Service, p *profiles.Profiles) *API { return &API{ service: svc, profiles: p, diff --git a/internal/api/dashboards/v1/http/create_test.go b/internal/api/dashboards/v1/http/create_test.go index 1582042..0d4c34f 100644 --- a/internal/api/dashboards/v1/http/create_test.go +++ b/internal/api/dashboards/v1/http/create_test.go @@ -2,8 +2,6 @@ package http import ( "context" - "errors" - "fmt" "net/http" "net/http/httptest" "strings" @@ -12,9 +10,18 @@ import ( "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" + "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/app/types" + mock "github.com/ozontech/seq-ui/internal/pkg/service/dashboards/mock" ) +func setupAPI(t *testing.T) (*API, *mock.MockService) { + ctrl := gomock.NewController(t) + mockedSvc := mock.NewMockService(ctrl) + p := profiles.New(mockedSvc) + return New(mockedSvc, p), mockedSvc +} + func TestServeCreate(t *testing.T) { userName := "unnamed" var profileID int64 = 1 @@ -22,10 +29,6 @@ func TestServeCreate(t *testing.T) { dashboardName := "my_dashboard" dashboardMeta := "my_meta" - formatReqBody := func(name, meta string) string { - return fmt.Sprintf(`{"name":%q,"meta":%q}`, name, meta) - } - type mockArgs struct { req types.CreateDashboardRequest resp string @@ -35,18 +38,16 @@ func TestServeCreate(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req createRequest + want createResponse + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantRespBody: fmt.Sprintf(`{"uuid":%q}`, dashboardUUID), - wantStatus: http.StatusOK, + name: "ok", + req: createRequest{Name: dashboardName, Meta: dashboardMeta}, + want: createResponse{UUID: dashboardUUID}, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ ProfileID: profileID, @@ -57,43 +58,21 @@ func TestServeCreate(t *testing.T) { }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_empty_name", - reqBody: formatReqBody("", dashboardMeta), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_empty_meta", - reqBody: formatReqBody(dashboardName, ""), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_random", - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusInternalServerError, + name: "err_svc", + req: createRequest{Name: dashboardName, Meta: dashboardMeta}, + wantErr: true, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ ProfileID: profileID, Name: dashboardName, Meta: dashboardMeta, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() diff --git a/internal/api/dashboards/v1/http/test_data.go b/internal/api/dashboards/v1/http/test_data.go index 4c1df04..e65a669 100644 --- a/internal/api/dashboards/v1/http/test_data.go +++ b/internal/api/dashboards/v1/http/test_data.go @@ -1,12 +1,17 @@ package http import ( + "errors" "testing" "github.com/ozontech/seq-ui/internal/api/dashboards/v1/test" repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" ) +var ( + errSomethingWrong = errors.New("something happened wrong") +) + func newTestData(t *testing.T) (*API, *repo_mock.MockDashboards) { mock, s, p := test.NewTestData(t) return New(s, p), mock diff --git a/internal/pkg/service/dashboards/mock/service.go b/internal/pkg/service/dashboards/mock/service.go new file mode 100644 index 0000000..31e43b8 --- /dev/null +++ b/internal/pkg/service/dashboards/mock/service.go @@ -0,0 +1,145 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ozontech/seq-ui/internal/pkg/service/dashboards (interfaces: Service) +// +// Generated by this command: +// +// mockgen -destination=internal/pkg/service/dashboards/mock/service.go github.com/ozontech/seq-ui/internal/pkg/service/dashboards Service +// + +// Package mock_dashboards is a generated GoMock package. +package mock_dashboards + +import ( + context "context" + reflect "reflect" + + types "github.com/ozontech/seq-ui/internal/app/types" + gomock "go.uber.org/mock/gomock" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder + isgomock struct{} +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// CreateDashboard mocks base method. +func (m *MockService) CreateDashboard(arg0 context.Context, arg1 types.CreateDashboardRequest) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateDashboard", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateDashboard indicates an expected call of CreateDashboard. +func (mr *MockServiceMockRecorder) CreateDashboard(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDashboard", reflect.TypeOf((*MockService)(nil).CreateDashboard), arg0, arg1) +} + +// DeleteDashboard mocks base method. +func (m *MockService) DeleteDashboard(arg0 context.Context, arg1 types.DeleteDashboardRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteDashboard", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteDashboard indicates an expected call of DeleteDashboard. +func (mr *MockServiceMockRecorder) DeleteDashboard(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDashboard", reflect.TypeOf((*MockService)(nil).DeleteDashboard), arg0, arg1) +} + +// GetAllDashboards mocks base method. +func (m *MockService) GetAllDashboards(arg0 context.Context, arg1 types.GetAllDashboardsRequest) (types.DashboardInfosWithOwner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllDashboards", arg0, arg1) + ret0, _ := ret[0].(types.DashboardInfosWithOwner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllDashboards indicates an expected call of GetAllDashboards. +func (mr *MockServiceMockRecorder) GetAllDashboards(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllDashboards", reflect.TypeOf((*MockService)(nil).GetAllDashboards), arg0, arg1) +} + +// GetDashboardByUUID mocks base method. +func (m *MockService) GetDashboardByUUID(arg0 context.Context, arg1 string) (types.Dashboard, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDashboardByUUID", arg0, arg1) + ret0, _ := ret[0].(types.Dashboard) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDashboardByUUID indicates an expected call of GetDashboardByUUID. +func (mr *MockServiceMockRecorder) GetDashboardByUUID(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDashboardByUUID", reflect.TypeOf((*MockService)(nil).GetDashboardByUUID), arg0, arg1) +} + +// GetMyDashboards mocks base method. +func (m *MockService) GetMyDashboards(arg0 context.Context, arg1 types.GetUserDashboardsRequest) (types.DashboardInfos, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMyDashboards", arg0, arg1) + ret0, _ := ret[0].(types.DashboardInfos) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMyDashboards indicates an expected call of GetMyDashboards. +func (mr *MockServiceMockRecorder) GetMyDashboards(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMyDashboards", reflect.TypeOf((*MockService)(nil).GetMyDashboards), arg0, arg1) +} + +// SearchDashboards mocks base method. +func (m *MockService) SearchDashboards(arg0 context.Context, arg1 types.SearchDashboardsRequest) (types.DashboardInfosWithOwner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchDashboards", arg0, arg1) + ret0, _ := ret[0].(types.DashboardInfosWithOwner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchDashboards indicates an expected call of SearchDashboards. +func (mr *MockServiceMockRecorder) SearchDashboards(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchDashboards", reflect.TypeOf((*MockService)(nil).SearchDashboards), arg0, arg1) +} + +// UpdateDashboard mocks base method. +func (m *MockService) UpdateDashboard(arg0 context.Context, arg1 types.UpdateDashboardRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDashboard", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateDashboard indicates an expected call of UpdateDashboard. +func (mr *MockServiceMockRecorder) UpdateDashboard(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDashboard", reflect.TypeOf((*MockService)(nil).UpdateDashboard), arg0, arg1) +} diff --git a/internal/pkg/service/dashboards.go b/internal/pkg/service/dashboards/service.go similarity index 67% rename from internal/pkg/service/dashboards.go rename to internal/pkg/service/dashboards/service.go index e87b391..1d68c10 100644 --- a/internal/pkg/service/dashboards.go +++ b/internal/pkg/service/dashboards/service.go @@ -1,41 +1,51 @@ -package service +package dashboards import ( "context" "github.com/gofrs/uuid" - "github.com/ozontech/seq-ui/internal/app/types" + "github.com/ozontech/seq-ui/internal/pkg/repository" ) -// GetAllDashboards from underlying repository. +type Service interface { + GetAllDashboards(context.Context, types.GetAllDashboardsRequest) (types.DashboardInfosWithOwner, error) + GetMyDashboards(context.Context, types.GetUserDashboardsRequest) (types.DashboardInfos, error) + GetDashboardByUUID(context.Context, string) (types.Dashboard, error) + CreateDashboard(context.Context, types.CreateDashboardRequest) (string, error) + UpdateDashboard(context.Context, types.UpdateDashboardRequest) error + DeleteDashboard(context.Context, types.DeleteDashboardRequest) error + SearchDashboards(context.Context, types.SearchDashboardsRequest) (types.DashboardInfosWithOwner, error) +} + +type service struct { + repo repository.Dashboards +} + func (s *service) GetAllDashboards(ctx context.Context, req types.GetAllDashboardsRequest) (types.DashboardInfosWithOwner, error) { if err := checkLimitOffset(req.Limit, req.Offset); err != nil { return nil, err } - return s.repo.Dashboards.GetAll(ctx, req) + return s.repo.GetAll(ctx, req) } -// GetMyDashboards from underlying repository. func (s *service) GetMyDashboards(ctx context.Context, req types.GetUserDashboardsRequest) (types.DashboardInfos, error) { if err := checkLimitOffset(req.Limit, req.Offset); err != nil { return nil, err } - return s.repo.Dashboards.GetMy(ctx, req) + return s.repo.GetMy(ctx, req) } -// GetDashboardByUUID from underlying repository. func (s *service) GetDashboardByUUID(ctx context.Context, id string) (types.Dashboard, error) { if err := checkUUID(id); err != nil { return types.Dashboard{}, err } - return s.repo.Dashboards.GetByUUID(ctx, id) + return s.repo.GetByUUID(ctx, id) } -// CreateDashboard in underlying repository. func (s *service) CreateDashboard(ctx context.Context, req types.CreateDashboardRequest) (string, error) { if req.Name == "" { return "", types.NewErrInvalidRequestField("empty 'name'") @@ -44,10 +54,9 @@ func (s *service) CreateDashboard(ctx context.Context, req types.CreateDashboard return "", types.NewErrInvalidRequestField("empty 'meta'") } - return s.repo.Dashboards.Create(ctx, req) + return s.repo.Create(ctx, req) } -// UpdateDashboard in underlying repository. func (s *service) UpdateDashboard(ctx context.Context, req types.UpdateDashboardRequest) error { if err := checkUUID(req.UUID); err != nil { return err @@ -56,24 +65,22 @@ func (s *service) UpdateDashboard(ctx context.Context, req types.UpdateDashboard return types.ErrEmptyUpdateRequest } - return s.repo.Dashboards.Update(ctx, req) + return s.repo.Update(ctx, req) } -// DeleteDashboard in underlying repository. func (s *service) DeleteDashboard(ctx context.Context, req types.DeleteDashboardRequest) error { if err := checkUUID(req.UUID); err != nil { return err } - return s.repo.Dashboards.Delete(ctx, req) + return s.repo.Delete(ctx, req) } -// SearchDashboards in underlying repository. func (s *service) SearchDashboards(ctx context.Context, req types.SearchDashboardsRequest) (types.DashboardInfosWithOwner, error) { if err := checkLimitOffset(req.Limit, req.Offset); err != nil { return nil, err } - return s.repo.Dashboards.Search(ctx, req) + return s.repo.Search(ctx, req) } func checkUUID(v string) error { diff --git a/internal/pkg/service/service.go b/internal/pkg/service/service.go index 4a34733..e8e2140 100644 --- a/internal/pkg/service/service.go +++ b/internal/pkg/service/service.go @@ -14,14 +14,6 @@ type Service interface { GetFavoriteQueries(context.Context, types.GetFavoriteQueriesRequest) (types.FavoriteQueries, error) GetOrCreateFavoriteQuery(context.Context, types.GetOrCreateFavoriteQueryRequest) (int64, error) DeleteFavoriteQuery(context.Context, types.DeleteFavoriteQueryRequest) error - - GetAllDashboards(context.Context, types.GetAllDashboardsRequest) (types.DashboardInfosWithOwner, error) - GetMyDashboards(context.Context, types.GetUserDashboardsRequest) (types.DashboardInfos, error) - GetDashboardByUUID(context.Context, string) (types.Dashboard, error) - CreateDashboard(context.Context, types.CreateDashboardRequest) (string, error) - UpdateDashboard(context.Context, types.UpdateDashboardRequest) error - DeleteDashboard(context.Context, types.DeleteDashboardRequest) error - SearchDashboards(context.Context, types.SearchDashboardsRequest) (types.DashboardInfosWithOwner, error) } type service struct { From 1aea51dc15d41bb1166bfc56becfbecad6b61b4e Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Mon, 22 Jun 2026 03:23:35 +0300 Subject: [PATCH 2/7] refactor http tests --- Makefile | 12 + cmd/seq-ui/main.go | 19 +- internal/api/dashboards/v1/dashboards.go | 9 +- internal/api/dashboards/v1/grpc/api.go | 9 +- internal/api/dashboards/v1/grpc/create.go | 11 +- .../api/dashboards/v1/grpc/create_test.go | 61 +-- internal/api/dashboards/v1/grpc/delete.go | 11 +- .../api/dashboards/v1/grpc/delete_test.go | 62 +-- internal/api/dashboards/v1/grpc/get_all.go | 6 +- .../api/dashboards/v1/grpc/get_all_test.go | 66 +--- .../api/dashboards/v1/grpc/get_by_uuid.go | 5 - .../dashboards/v1/grpc/get_by_uuid_test.go | 56 +-- internal/api/dashboards/v1/grpc/get_my.go | 11 +- .../api/dashboards/v1/grpc/get_my_test.go | 68 +--- internal/api/dashboards/v1/grpc/search.go | 6 +- .../api/dashboards/v1/grpc/search_test.go | 80 ++-- internal/api/dashboards/v1/grpc/test_data.go | 28 +- internal/api/dashboards/v1/grpc/update.go | 15 +- .../api/dashboards/v1/grpc/update_test.go | 135 +------ internal/api/dashboards/v1/http/api.go | 9 +- internal/api/dashboards/v1/http/create.go | 12 +- .../api/dashboards/v1/http/create_test.go | 53 +-- internal/api/dashboards/v1/http/delete.go | 12 +- .../api/dashboards/v1/http/delete_test.go | 80 +--- internal/api/dashboards/v1/http/get_all.go | 7 +- .../api/dashboards/v1/http/get_all_test.go | 90 ++--- .../api/dashboards/v1/http/get_by_uuid.go | 6 - .../dashboards/v1/http/get_by_uuid_test.go | 79 ++-- internal/api/dashboards/v1/http/get_my.go | 12 +- .../api/dashboards/v1/http/get_my_test.go | 100 ++--- internal/api/dashboards/v1/http/search.go | 6 - .../api/dashboards/v1/http/search_test.go | 124 ++---- internal/api/dashboards/v1/http/test_data.go | 31 +- internal/api/dashboards/v1/http/update.go | 16 +- .../api/dashboards/v1/http/update_test.go | 167 ++------ internal/api/dashboards/v1/test/data.go | 23 -- .../api/massexport/v1/grpc/cancel_test.go | 68 ++++ internal/api/massexport/v1/grpc/check_test.go | 80 ++++ .../api/massexport/v1/grpc/get_all_test.go | 86 ++++ .../api/massexport/v1/grpc/restore_test.go | 64 +++ internal/api/massexport/v1/grpc/start_test.go | 122 ++++++ internal/api/massexport/v1/grpc/test_data.go | 28 ++ .../api/massexport/v1/http/cancel_test.go | 63 +++ internal/api/massexport/v1/http/check_test.go | 83 ++++ .../api/massexport/v1/http/get_all_test.go | 83 ++++ .../api/massexport/v1/http/restore_test.go | 63 +++ internal/api/massexport/v1/http/start_test.go | 118 ++++++ internal/api/massexport/v1/http/test_data.go | 28 ++ .../api/seqapi/v1/grpc/aggregation_test.go | 53 ++- internal/api/seqapi/v1/grpc/api.go | 8 +- .../api/seqapi/v1/grpc/cancel_async_search.go | 12 +- .../v1/grpc/cancel_async_search_test.go | 131 ++---- .../api/seqapi/v1/grpc/cluster_status_test.go | 72 +++- .../api/seqapi/v1/grpc/delete_async_search.go | 12 +- .../v1/grpc/delete_async_search_test.go | 140 ++----- internal/api/seqapi/v1/grpc/events_test.go | 84 ++-- .../v1/grpc/fetch_async_search_result.go | 5 +- .../v1/grpc/fetch_async_search_result_test.go | 133 ++++--- internal/api/seqapi/v1/grpc/fields_test.go | 39 +- .../seqapi/v1/grpc/get_async_searches_list.go | 5 +- .../v1/grpc/get_async_searches_list_test.go | 152 +++---- internal/api/seqapi/v1/grpc/get_envs_test.go | 1 - internal/api/seqapi/v1/grpc/histogram_test.go | 28 +- internal/api/seqapi/v1/grpc/limits_test.go | 4 +- .../api/seqapi/v1/grpc/logs_lifespan_test.go | 44 +-- internal/api/seqapi/v1/grpc/search_test.go | 29 +- .../api/seqapi/v1/grpc/start_async_search.go | 12 +- .../seqapi/v1/grpc/start_async_search_test.go | 103 +++-- internal/api/seqapi/v1/grpc/test_data.go | 48 ++- .../api/seqapi/v1/http/aggregation_test.go | 172 ++++---- .../api/seqapi/v1/http/aggregation_ts_test.go | 7 +- internal/api/seqapi/v1/http/api.go | 8 +- .../api/seqapi/v1/http/cancel_async_search.go | 10 +- .../v1/http/cancel_async_search_test.go | 166 +++----- .../api/seqapi/v1/http/cluster_status_test.go | 67 ++-- .../api/seqapi/v1/http/delete_async_search.go | 10 +- .../v1/http/delete_async_search_test.go | 178 +++------ internal/api/seqapi/v1/http/events_test.go | 177 ++++----- internal/api/seqapi/v1/http/export_test.go | 172 ++++---- .../v1/http/fetch_async_search_result_test.go | 335 +++++++++++----- internal/api/seqapi/v1/http/fields_test.go | 205 +++++----- .../v1/http/get_async_searches_list_test.go | 374 ++++++++++-------- internal/api/seqapi/v1/http/get_envs_test.go | 128 +++--- internal/api/seqapi/v1/http/histogram_test.go | 99 +++-- internal/api/seqapi/v1/http/limits_test.go | 39 +- .../api/seqapi/v1/http/logs_lifespan_test.go | 76 ++-- internal/api/seqapi/v1/http/search_test.go | 339 +++++++++------- .../api/seqapi/v1/http/start_async_search.go | 8 +- .../seqapi/v1/http/start_async_search_test.go | 191 +++++---- internal/api/seqapi/v1/http/test_data.go | 68 +++- internal/api/seqapi/v1/seqapi.go | 8 +- internal/api/seqapi/v1/test/data.go | 14 +- internal/api/userprofile/v1/grpc/api.go | 11 +- .../userprofile/v1/grpc/favorite_queries.go | 29 +- .../v1/grpc/favorite_queries_test.go | 154 ++------ internal/api/userprofile/v1/grpc/test_data.go | 33 +- .../api/userprofile/v1/grpc/user_profiles.go | 8 +- .../userprofile/v1/grpc/user_profiles_test.go | 151 +------ internal/api/userprofile/v1/http/api.go | 11 +- .../userprofile/v1/http/favorite_queries.go | 33 +- .../v1/http/favorite_queries_test.go | 274 ++++--------- internal/api/userprofile/v1/http/test_data.go | 46 ++- .../api/userprofile/v1/http/user_profiles.go | 4 +- .../userprofile/v1/http/user_profiles_test.go | 223 +++-------- internal/api/userprofile/v1/test/data.go | 34 -- internal/api/userprofile/v1/userprofile.go | 9 +- internal/app/auth/oidc.go | 7 +- .../service/async_searches/mock/service.go | 117 ++++++ .../pkg/service/async_searches/service.go | 69 ++-- internal/pkg/service/dashboards/service.go | 48 +++ internal/pkg/service/favorite_queries.go | 30 -- .../pkg/service/massexport/mock/service.go | 115 ++++++ .../{api => pkg/service}/profiles/profiles.go | 23 +- internal/pkg/service/service.go | 27 -- internal/pkg/service/user_profiles.go | 27 -- .../pkg/service/userprofile/mock/service.go | 115 ++++++ internal/pkg/service/userprofile/service.go | 92 +++++ 117 files changed, 4100 insertions(+), 3939 deletions(-) delete mode 100644 internal/api/dashboards/v1/test/data.go create mode 100644 internal/api/massexport/v1/grpc/cancel_test.go create mode 100644 internal/api/massexport/v1/grpc/check_test.go create mode 100644 internal/api/massexport/v1/grpc/get_all_test.go create mode 100644 internal/api/massexport/v1/grpc/restore_test.go create mode 100644 internal/api/massexport/v1/grpc/start_test.go create mode 100644 internal/api/massexport/v1/grpc/test_data.go create mode 100644 internal/api/massexport/v1/http/cancel_test.go create mode 100644 internal/api/massexport/v1/http/check_test.go create mode 100644 internal/api/massexport/v1/http/get_all_test.go create mode 100644 internal/api/massexport/v1/http/restore_test.go create mode 100644 internal/api/massexport/v1/http/start_test.go create mode 100644 internal/api/massexport/v1/http/test_data.go delete mode 100644 internal/api/userprofile/v1/test/data.go create mode 100644 internal/pkg/service/async_searches/mock/service.go delete mode 100644 internal/pkg/service/favorite_queries.go create mode 100644 internal/pkg/service/massexport/mock/service.go rename internal/{api => pkg/service}/profiles/profiles.go (71%) delete mode 100644 internal/pkg/service/service.go delete mode 100644 internal/pkg/service/user_profiles.go create mode 100644 internal/pkg/service/userprofile/mock/service.go create mode 100644 internal/pkg/service/userprofile/service.go diff --git a/Makefile b/Makefile index d9dda90..f236185 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,18 @@ mock: -destination=internal/pkg/service/dashboards/mock/service.go \ github.com/ozontech/seq-ui/internal/pkg/service/dashboards \ Service + PATH="$(LOCAL_BIN):$(PATH)" mockgen \ + -destination=internal/pkg/service/async_searches/mock/service.go \ + github.com/ozontech/seq-ui/internal/pkg/service/async_searches \ + Service + PATH="$(LOCAL_BIN):$(PATH)" mockgen \ + -destination=internal/pkg/service/userprofile/mock/service.go \ + github.com/ozontech/seq-ui/internal/pkg/service/userprofile \ + Service + PATH="$(LOCAL_BIN):$(PATH)" mockgen \ + -destination=internal/pkg/service/massexport/mock/service.go \ + github.com/ozontech/seq-ui/internal/pkg/service/massexport \ + Service .PHONY: protoc protoc: diff --git a/cmd/seq-ui/main.go b/cmd/seq-ui/main.go index 9450352..faa4c21 100644 --- a/cmd/seq-ui/main.go +++ b/cmd/seq-ui/main.go @@ -21,7 +21,6 @@ import ( dashboards_v1 "github.com/ozontech/seq-ui/internal/api/dashboards/v1" errorgroups_v1 "github.com/ozontech/seq-ui/internal/api/errorgroups/v1" massexport_v1 "github.com/ozontech/seq-ui/internal/api/massexport/v1" - "github.com/ozontech/seq-ui/internal/api/profiles" seqapi_v1 "github.com/ozontech/seq-ui/internal/api/seqapi/v1" userprofile_v1 "github.com/ozontech/seq-ui/internal/api/userprofile/v1" "github.com/ozontech/seq-ui/internal/app/config" @@ -30,12 +29,14 @@ import ( "github.com/ozontech/seq-ui/internal/pkg/client/seqdb" "github.com/ozontech/seq-ui/internal/pkg/repository" repositorych "github.com/ozontech/seq-ui/internal/pkg/repository_ch" - "github.com/ozontech/seq-ui/internal/pkg/service" asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches" + dashboards "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" "github.com/ozontech/seq-ui/internal/pkg/service/errorgroups" "github.com/ozontech/seq-ui/internal/pkg/service/massexport" "github.com/ozontech/seq-ui/internal/pkg/service/massexport/filestore" "github.com/ozontech/seq-ui/internal/pkg/service/massexport/sessionstore" + "github.com/ozontech/seq-ui/internal/pkg/service/profiles" + userprofile "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" "github.com/ozontech/seq-ui/logger" "github.com/ozontech/seq-ui/tracing" ) @@ -151,23 +152,23 @@ func initApp(ctx context.Context, cfg config.Config) *api.Registrar { } var ( - asyncSearchesService *asyncsearches.Service - p *profiles.Profiles + asyncSearchesService asyncsearches.Service userProfileV1 *userprofile_v1.UserProfile dashboardsV1 *dashboards_v1.Dashboards ) if db != nil { repo := repository.New(db, cfg.Server.DB.RequestTimeout) - svc := service.New(repo) - p = profiles.New(svc) + userProfilesSvc := userprofile.New(repo.UserProfiles, repo.FavoriteQueries) + dashboardsSvc := dashboards.New(repo.Dashboards) + profiles.InitProfiles(userProfilesSvc) - userProfileV1 = userprofile_v1.New(svc, p) - dashboardsV1 = dashboards_v1.New(svc, p) + userProfileV1 = userprofile_v1.New(userProfilesSvc) + dashboardsV1 = dashboards_v1.New(dashboardsSvc) asyncSearchesService = asyncsearches.New(ctx, repo, defaultClient, cfg.Handlers.AsyncSearch) } - seqApiV1 := seqapi_v1.New(cfg.Handlers.SeqAPI, seqDBClients, inmemWithRedisCache, redisCache, asyncSearchesService, p) + seqApiV1 := seqapi_v1.New(cfg.Handlers.SeqAPI, seqDBClients, inmemWithRedisCache, redisCache, asyncSearchesService) logger.Info("initializing clickhouse") ch, err := initClickHouse(ctx, cfg.Server.CH) diff --git a/internal/api/dashboards/v1/dashboards.go b/internal/api/dashboards/v1/dashboards.go index cdb62f1..f245456 100644 --- a/internal/api/dashboards/v1/dashboards.go +++ b/internal/api/dashboards/v1/dashboards.go @@ -5,8 +5,7 @@ import ( grpc_api "github.com/ozontech/seq-ui/internal/api/dashboards/v1/grpc" http_api "github.com/ozontech/seq-ui/internal/api/dashboards/v1/http" - "github.com/ozontech/seq-ui/internal/api/profiles" - "github.com/ozontech/seq-ui/internal/pkg/service" + dashboards "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" ) type Dashboards struct { @@ -14,10 +13,10 @@ type Dashboards struct { httpAPI *http_api.API } -func New(svc service.Service, p *profiles.Profiles) *Dashboards { +func New(svc dashboards.Service) *Dashboards { return &Dashboards{ - grpcAPI: grpc_api.New(svc, p), - httpAPI: http_api.New(svc, p), + grpcAPI: grpc_api.New(svc), + httpAPI: http_api.New(svc), } } diff --git a/internal/api/dashboards/v1/grpc/api.go b/internal/api/dashboards/v1/grpc/api.go index dfc6457..1a680b1 100644 --- a/internal/api/dashboards/v1/grpc/api.go +++ b/internal/api/dashboards/v1/grpc/api.go @@ -1,7 +1,6 @@ package grpc import ( - "github.com/ozontech/seq-ui/internal/api/profiles" dashboardsservice "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" "github.com/ozontech/seq-ui/pkg/dashboards/v1" ) @@ -9,13 +8,11 @@ import ( type API struct { dashboards.UnimplementedDashboardsServiceServer - service dashboardsservice.Service - profiles *profiles.Profiles + service dashboardsservice.Service } -func New(svc dashboardsservice.Service, p *profiles.Profiles) *API { +func New(svc dashboardsservice.Service) *API { return &API{ - service: svc, - profiles: p, + service: svc, } } diff --git a/internal/api/dashboards/v1/grpc/create.go b/internal/api/dashboards/v1/grpc/create.go index b6f09cf..66e44a0 100644 --- a/internal/api/dashboards/v1/grpc/create.go +++ b/internal/api/dashboards/v1/grpc/create.go @@ -22,16 +22,11 @@ func (a *API) Create(ctx context.Context, req *dashboards.CreateRequest) (*dashb }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - request := types.CreateDashboardRequest{ - ProfileID: profileID, - Name: req.Name, - Meta: req.Meta, + Name: req.Name, + Meta: req.Meta, } + uuid, err := a.service.CreateDashboard(ctx, request) if err != nil { return nil, grpcutil.ProcessError(err) diff --git a/internal/api/dashboards/v1/grpc/create_test.go b/internal/api/dashboards/v1/grpc/create_test.go index 30a5c25..4cb15ab 100644 --- a/internal/api/dashboards/v1/grpc/create_test.go +++ b/internal/api/dashboards/v1/grpc/create_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,12 +14,6 @@ import ( ) func TestCreate(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName := "my_dashboard" - dashboardMeta := "my_meta" - type mockArgs struct { req types.CreateDashboardRequest resp string @@ -35,10 +28,9 @@ func TestCreate(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &dashboards.CreateRequest{ Name: dashboardName, Meta: dashboardMeta, @@ -49,34 +41,14 @@ func TestCreate(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ - ProfileID: profileID, - Name: dashboardName, - Meta: dashboardMeta, + Name: dashboardName, + Meta: dashboardMeta, }, resp: dashboardUUID, }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_empty_name", - req: &dashboards.CreateRequest{ - Meta: dashboardMeta, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc_empty_meta", - req: &dashboards.CreateRequest{ - Name: dashboardName, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_random", + name: "err_svc", req: &dashboards.CreateRequest{ Name: dashboardName, Meta: dashboardMeta, @@ -84,33 +56,28 @@ func TestCreate(t *testing.T) { wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ - ProfileID: profileID, - Name: dashboardName, - Meta: dashboardMeta, + Name: dashboardName, + Meta: dashboardMeta, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Create(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + CreateDashboard(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - got, err := api.Create(ctx, tt.req) + got, err := api.Create(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/grpc/delete.go b/internal/api/dashboards/v1/grpc/delete.go index e2408f3..5d286a7 100644 --- a/internal/api/dashboards/v1/grpc/delete.go +++ b/internal/api/dashboards/v1/grpc/delete.go @@ -22,16 +22,11 @@ func (a *API) Delete(ctx context.Context, req *dashboards.DeleteRequest) (*dashb }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - request := types.DeleteDashboardRequest{ - UUID: req.Uuid, - ProfileID: profileID, + UUID: req.Uuid, } - if err = a.service.DeleteDashboard(ctx, request); err != nil { + + if err := a.service.DeleteDashboard(ctx, request); err != nil { return nil, grpcutil.ProcessError(err) } diff --git a/internal/api/dashboards/v1/grpc/delete_test.go b/internal/api/dashboards/v1/grpc/delete_test.go index 9401f59..a9bd68a 100644 --- a/internal/api/dashboards/v1/grpc/delete_test.go +++ b/internal/api/dashboards/v1/grpc/delete_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,10 +14,6 @@ import ( ) func TestDelete(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - type mockArgs struct { req types.DeleteDashboardRequest err error @@ -32,10 +27,9 @@ func TestDelete(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &dashboards.DeleteRequest{ Uuid: dashboardUUID, }, @@ -43,71 +37,39 @@ func TestDelete(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, - ProfileID: profileID, + UUID: dashboardUUID, }, }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_uuid", - req: &dashboards.DeleteRequest{ - Uuid: "invalid-uuid", - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_permission_denied", - req: &dashboards.DeleteRequest{ - Uuid: dashboardUUID, - }, - wantCode: codes.PermissionDenied, - mockArgs: &mockArgs{ - req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, - ProfileID: profileID, - }, - err: types.ErrPermissionDenied, - }, - }, - { - name: "err_repo_random", + name: "err_svc", req: &dashboards.DeleteRequest{ Uuid: dashboardUUID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, - ProfileID: profileID, + UUID: dashboardUUID, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Delete(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + DeleteDashboard(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } - got, err := api.Delete(ctx, tt.req) + got, err := api.Delete(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/grpc/get_all.go b/internal/api/dashboards/v1/grpc/get_all.go index 57ae765..1ee7941 100644 --- a/internal/api/dashboards/v1/grpc/get_all.go +++ b/internal/api/dashboards/v1/grpc/get_all.go @@ -26,15 +26,11 @@ func (a *API) GetAll(ctx context.Context, req *dashboards.GetAllRequest) (*dashb }, ) - // check auth and create profile if its doesn't exist - if _, err := a.profiles.GeIDFromContext(ctx); err != nil { - return nil, grpcutil.ProcessError(err) - } - request := types.GetAllDashboardsRequest{ Limit: int(req.Limit), Offset: int(req.Offset), } + dis, err := a.service.GetAllDashboards(ctx, request) if err != nil { return nil, grpcutil.ProcessError(err) diff --git a/internal/api/dashboards/v1/grpc/get_all_test.go b/internal/api/dashboards/v1/grpc/get_all_test.go index 46e3f18..b9a24ac 100644 --- a/internal/api/dashboards/v1/grpc/get_all_test.go +++ b/internal/api/dashboards/v1/grpc/get_all_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,9 +14,6 @@ import ( ) func TestGetAll(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - type mockArgs struct { req types.GetAllDashboardsRequest resp types.DashboardInfosWithOwner @@ -32,13 +28,12 @@ func TestGetAll(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &dashboards.GetAllRequest{ - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), }, want: &dashboards.GetAllResponse{ Dashboards: []*dashboards.GetAllResponse_Dashboard{ @@ -49,8 +44,8 @@ func TestGetAll(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ - Limit: 2, - Offset: 0, + Limit: limit, + Offset: offset, }, resp: types.DashboardInfosWithOwner{ { @@ -71,61 +66,36 @@ func TestGetAll(t *testing.T) { }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_limit", - req: &dashboards.GetAllRequest{ - Limit: 0, - Offset: 0, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc_invalid_offset", + name: "err_svc", req: &dashboards.GetAllRequest{ - Limit: 2, - Offset: -10, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_random", - req: &dashboards.GetAllRequest{ - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ - Limit: 2, - Offset: 0, + Limit: limit, + Offset: offset, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetAll(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetAllDashboards(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - got, err := api.GetAll(ctx, tt.req) + got, err := api.GetAll(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/grpc/get_by_uuid.go b/internal/api/dashboards/v1/grpc/get_by_uuid.go index 0db45b1..91df1ab 100644 --- a/internal/api/dashboards/v1/grpc/get_by_uuid.go +++ b/internal/api/dashboards/v1/grpc/get_by_uuid.go @@ -21,11 +21,6 @@ func (a *API) GetByUUID(ctx context.Context, req *dashboards.GetByUUIDRequest) ( }, ) - // check auth and create profile if its doesn't exist - if _, err := a.profiles.GeIDFromContext(ctx); err != nil { - return nil, grpcutil.ProcessError(err) - } - d, err := a.service.GetDashboardByUUID(ctx, req.Uuid) if err != nil { return nil, grpcutil.ProcessError(err) diff --git a/internal/api/dashboards/v1/grpc/get_by_uuid_test.go b/internal/api/dashboards/v1/grpc/get_by_uuid_test.go index a4d4385..ac0c639 100644 --- a/internal/api/dashboards/v1/grpc/get_by_uuid_test.go +++ b/internal/api/dashboards/v1/grpc/get_by_uuid_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,13 +14,6 @@ import ( ) func TestGetByUUID(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName := "my_dashboard" - dashboardMeta := "my_meta" - dashboardOwner := "owner" - type mockArgs struct { uuid string resp types.Dashboard @@ -36,10 +28,9 @@ func TestGetByUUID(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &dashboards.GetByUUIDRequest{ Uuid: dashboardUUID, }, @@ -59,59 +50,32 @@ func TestGetByUUID(t *testing.T) { }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_uuid", - req: &dashboards.GetByUUIDRequest{ - Uuid: "invalid-uuid", - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_not_found", - req: &dashboards.GetByUUIDRequest{ - Uuid: dashboardUUID, - }, - wantCode: codes.NotFound, - mockArgs: &mockArgs{ - uuid: dashboardUUID, - err: types.ErrNotFound, - }, - }, - { - name: "err_repo_random", + name: "err_svc", req: &dashboards.GetByUUIDRequest{ Uuid: dashboardUUID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ uuid: dashboardUUID, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetByUUID(gomock.Any(), tt.mockArgs.uuid). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetDashboardByUUID(gomock.Any(), tt.mockArgs.uuid). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - got, err := api.GetByUUID(ctx, tt.req) + got, err := api.GetByUUID(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/grpc/get_my.go b/internal/api/dashboards/v1/grpc/get_my.go index d684019..b65f0cb 100644 --- a/internal/api/dashboards/v1/grpc/get_my.go +++ b/internal/api/dashboards/v1/grpc/get_my.go @@ -26,16 +26,11 @@ func (a *API) GetMy(ctx context.Context, req *dashboards.GetMyRequest) (*dashboa }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - request := types.GetUserDashboardsRequest{ - ProfileID: profileID, - Limit: int(req.Limit), - Offset: int(req.Offset), + Limit: int(req.Limit), + Offset: int(req.Offset), } + dis, err := a.service.GetMyDashboards(ctx, request) if err != nil { return nil, grpcutil.ProcessError(err) diff --git a/internal/api/dashboards/v1/grpc/get_my_test.go b/internal/api/dashboards/v1/grpc/get_my_test.go index e0dda27..bab0f8b 100644 --- a/internal/api/dashboards/v1/grpc/get_my_test.go +++ b/internal/api/dashboards/v1/grpc/get_my_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,9 +14,6 @@ import ( ) func TestGetMy(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - type mockArgs struct { req types.GetUserDashboardsRequest resp types.DashboardInfos @@ -32,13 +28,12 @@ func TestGetMy(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &dashboards.GetMyRequest{ - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), }, want: &dashboards.GetMyResponse{ Dashboards: []*dashboards.GetMyResponse_Dashboard{ @@ -49,9 +44,8 @@ func TestGetMy(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - ProfileID: profileID, - Limit: 2, - Offset: 0, + Limit: limit, + Offset: offset, }, resp: types.DashboardInfos{ {UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, @@ -60,62 +54,36 @@ func TestGetMy(t *testing.T) { }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_limit", - req: &dashboards.GetMyRequest{ - Limit: 0, - Offset: 0, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc_invalid_offset", + name: "err_svc", req: &dashboards.GetMyRequest{ - Limit: 2, - Offset: -10, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_random", - req: &dashboards.GetMyRequest{ - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - ProfileID: profileID, - Limit: 2, - Offset: 0, + Limit: limit, + Offset: offset, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetMy(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetMyDashboards(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - got, err := api.GetMy(ctx, tt.req) + got, err := api.GetMy(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/grpc/search.go b/internal/api/dashboards/v1/grpc/search.go index 45213fd..a0bb271 100644 --- a/internal/api/dashboards/v1/grpc/search.go +++ b/internal/api/dashboards/v1/grpc/search.go @@ -40,16 +40,12 @@ func (a *API) Search(ctx context.Context, req *dashboards.SearchRequest) (*dashb span.SetAttributes(spanAttributes...) - // check auth and create profile if its doesn't exist - if _, err := a.profiles.GeIDFromContext(ctx); err != nil { - return nil, grpcutil.ProcessError(err) - } - request := types.SearchDashboardsRequest{ Query: req.Query, Limit: int(req.Limit), Offset: int(req.Offset), } + if req.Filter != nil { request.Filter = &types.SearchDashboardsFilter{ OwnerName: req.Filter.OwnerName, diff --git a/internal/api/dashboards/v1/grpc/search_test.go b/internal/api/dashboards/v1/grpc/search_test.go index 4b08c62..95d1c3d 100644 --- a/internal/api/dashboards/v1/grpc/search_test.go +++ b/internal/api/dashboards/v1/grpc/search_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,9 +14,6 @@ import ( ) func TestSearch(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - type mockArgs struct { req types.SearchDashboardsRequest resp types.DashboardInfosWithOwner @@ -32,14 +28,13 @@ func TestSearch(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &dashboards.SearchRequest{ Query: "test", - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), }, want: &dashboards.SearchResponse{ Dashboards: []*dashboards.SearchResponse_Dashboard{ @@ -51,8 +46,8 @@ func TestSearch(t *testing.T) { mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: "test", - Limit: 2, - Offset: 0, + Limit: limit, + Offset: offset, }, resp: types.DashboardInfosWithOwner{ { @@ -73,11 +68,11 @@ func TestSearch(t *testing.T) { }, }, { - name: "success_with_filter", + name: "ok_with_filter", req: &dashboards.SearchRequest{ Query: "test", - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), Filter: &dashboards.SearchRequest_Filter{ OwnerName: &userName, }, @@ -91,11 +86,9 @@ func TestSearch(t *testing.T) { mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: "test", - Limit: 2, - Offset: 0, - Filter: &types.SearchDashboardsFilter{ - OwnerName: &userName, - }, + Limit: limit, + Offset: offset, + Filter: filter, }, resp: types.DashboardInfosWithOwner{ { @@ -109,63 +102,38 @@ func TestSearch(t *testing.T) { }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_limit", - req: &dashboards.SearchRequest{ - Limit: 0, - Offset: 0, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc_invalid_offset", - req: &dashboards.SearchRequest{ - Limit: 2, - Offset: -10, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_random", + name: "err_svc", req: &dashboards.SearchRequest{ Query: "test", - Limit: 2, - Offset: 0, + Limit: int32(limit), + Offset: int32(offset), }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: "test", - Limit: 2, - Offset: 0, + Limit: limit, + Offset: offset, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Search(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + SearchDashboards(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - got, err := api.Search(ctx, tt.req) + got, err := api.Search(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/grpc/test_data.go b/internal/api/dashboards/v1/grpc/test_data.go index d230b21..e59d9b1 100644 --- a/internal/api/dashboards/v1/grpc/test_data.go +++ b/internal/api/dashboards/v1/grpc/test_data.go @@ -1,13 +1,31 @@ package grpc import ( + "errors" "testing" - "github.com/ozontech/seq-ui/internal/api/dashboards/v1/test" - repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/app/types" + mock "github.com/ozontech/seq-ui/internal/pkg/service/dashboards/mock" +) + +var ( + errSomethingWrong = errors.New("something happened wrong") + userName = "unnamed" + dashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" + dashboardName = "my_dashboard" + dashboardMeta = "my_meta" + dashboardOwner = "owner" + limit = 2 + offset = 0 + filter = &types.SearchDashboardsFilter{ + OwnerName: &userName, + } ) -func newTestData(t *testing.T) (*API, *repo_mock.MockDashboards) { - mock, s, p := test.NewTestData(t) - return New(s, p), mock +func setupAPI(t *testing.T) (*API, *mock.MockService) { + ctrl := gomock.NewController(t) + mockedSvc := mock.NewMockService(ctrl) + return New(mockedSvc), mockedSvc } diff --git a/internal/api/dashboards/v1/grpc/update.go b/internal/api/dashboards/v1/grpc/update.go index f382c4d..3151157 100644 --- a/internal/api/dashboards/v1/grpc/update.go +++ b/internal/api/dashboards/v1/grpc/update.go @@ -26,18 +26,13 @@ func (a *API) Update(ctx context.Context, req *dashboards.UpdateRequest) (*dashb }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - request := types.UpdateDashboardRequest{ - UUID: req.Uuid, - ProfileID: profileID, - Name: req.Name, - Meta: req.Meta, + UUID: req.Uuid, + Name: req.Name, + Meta: req.Meta, } - if err = a.service.UpdateDashboard(ctx, request); err != nil { + + if err := a.service.UpdateDashboard(ctx, request); err != nil { return nil, grpcutil.ProcessError(err) } diff --git a/internal/api/dashboards/v1/grpc/update_test.go b/internal/api/dashboards/v1/grpc/update_test.go index 1fa2e25..d0151a8 100644 --- a/internal/api/dashboards/v1/grpc/update_test.go +++ b/internal/api/dashboards/v1/grpc/update_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,12 +14,6 @@ import ( ) func TestUpdate(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName := "dashboard" - dashboardMeta := "meta" - type mockArgs struct { req types.UpdateDashboardRequest err error @@ -34,10 +27,9 @@ func TestUpdate(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success_all", + name: "ok", req: &dashboards.UpdateRequest{ Uuid: dashboardUUID, Name: &dashboardName, @@ -47,104 +39,14 @@ func TestUpdate(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - }, - }, - { - name: "success_only_name", - req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - Name: &dashboardName, - }, - want: &dashboards.UpdateResponse{}, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, + UUID: dashboardUUID, + Name: &dashboardName, + Meta: &dashboardMeta, }, }, }, { - name: "success_only_meta", - req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - Meta: &dashboardMeta, - }, - want: &dashboards.UpdateResponse{}, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Meta: &dashboardMeta, - }, - }, - }, - { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_uuid", - req: &dashboards.UpdateRequest{ - Uuid: "invalid-uuid", - Name: &dashboardName, - Meta: &dashboardMeta, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc_empty_request", - req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_not_found", - req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - wantCode: codes.NotFound, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - err: types.ErrNotFound, - }, - }, - { - name: "err_repo_permission_denied", - req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - wantCode: codes.PermissionDenied, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - err: types.ErrPermissionDenied, - }, - }, - { - name: "err_repo_random", + name: "err_svc", req: &dashboards.UpdateRequest{ Uuid: dashboardUUID, Name: &dashboardName, @@ -153,34 +55,29 @@ func TestUpdate(t *testing.T) { wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + UUID: dashboardUUID, + Name: &dashboardName, + Meta: &dashboardMeta, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Update(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + UpdateDashboard(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } - got, err := api.Update(ctx, tt.req) + got, err := api.Update(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/dashboards/v1/http/api.go b/internal/api/dashboards/v1/http/api.go index 02e67f2..ed506af 100644 --- a/internal/api/dashboards/v1/http/api.go +++ b/internal/api/dashboards/v1/http/api.go @@ -3,20 +3,17 @@ package http import ( "github.com/go-chi/chi/v5" - "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/app/types" dashboardsservice "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" ) type API struct { - service dashboardsservice.Service - profiles *profiles.Profiles + service dashboardsservice.Service } -func New(svc dashboardsservice.Service, p *profiles.Profiles) *API { +func New(svc dashboardsservice.Service) *API { return &API{ - service: svc, - profiles: p, + service: svc, } } diff --git a/internal/api/dashboards/v1/http/create.go b/internal/api/dashboards/v1/http/create.go index 70f7179..fef7a33 100644 --- a/internal/api/dashboards/v1/http/create.go +++ b/internal/api/dashboards/v1/http/create.go @@ -40,17 +40,11 @@ func (a *API) serveCreate(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - req := types.CreateDashboardRequest{ - ProfileID: profileID, - Name: httpReq.Name, - Meta: httpReq.Meta, + Name: httpReq.Name, + Meta: httpReq.Meta, } + uuid, err := a.service.CreateDashboard(ctx, req) if err != nil { httputil.ProcessError(wr, err) diff --git a/internal/api/dashboards/v1/http/create_test.go b/internal/api/dashboards/v1/http/create_test.go index 0d4c34f..29be020 100644 --- a/internal/api/dashboards/v1/http/create_test.go +++ b/internal/api/dashboards/v1/http/create_test.go @@ -1,34 +1,16 @@ package http import ( - "context" "net/http" - "net/http/httptest" - "strings" "testing" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" - "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/app/types" - mock "github.com/ozontech/seq-ui/internal/pkg/service/dashboards/mock" ) -func setupAPI(t *testing.T) (*API, *mock.MockService) { - ctrl := gomock.NewController(t) - mockedSvc := mock.NewMockService(ctrl) - p := profiles.New(mockedSvc) - return New(mockedSvc, p), mockedSvc -} - func TestServeCreate(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName := "my_dashboard" - dashboardMeta := "my_meta" - type mockArgs struct { req types.CreateDashboardRequest resp string @@ -50,9 +32,8 @@ func TestServeCreate(t *testing.T) { want: createResponse{UUID: dashboardUUID}, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ - ProfileID: profileID, - Name: dashboardName, - Meta: dashboardMeta, + Name: dashboardName, + Meta: dashboardMeta, }, resp: dashboardUUID, }, @@ -63,9 +44,8 @@ func TestServeCreate(t *testing.T) { wantErr: true, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ - ProfileID: profileID, - Name: dashboardName, - Meta: dashboardMeta, + Name: dashboardName, + Meta: dashboardMeta, }, err: errSomethingWrong, }, @@ -76,23 +56,22 @@ func TestServeCreate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) - req := httptest.NewRequest(http.MethodPost, "/dashboards/v1/", strings.NewReader(tt.reqBody)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Create(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + CreateDashboard(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveCreate, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[createRequest, createResponse]{ + Method: http.MethodPost, + Target: "/dashboards/v1/", + Req: tt.req, + Handler: api.serveCreate, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/http/delete.go b/internal/api/dashboards/v1/http/delete.go index d7cfcc4..8a2c958 100644 --- a/internal/api/dashboards/v1/http/delete.go +++ b/internal/api/dashboards/v1/http/delete.go @@ -35,17 +35,11 @@ func (a *API) serveDelete(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - req := types.DeleteDashboardRequest{ - UUID: uuid, - ProfileID: profileID, + UUID: uuid, } - err = a.service.DeleteDashboard(ctx, req) + + err := a.service.DeleteDashboard(ctx, req) if err != nil { httputil.ProcessError(wr, err) return diff --git a/internal/api/dashboards/v1/http/delete_test.go b/internal/api/dashboards/v1/http/delete_test.go index 506e112..d7308ab 100644 --- a/internal/api/dashboards/v1/http/delete_test.go +++ b/internal/api/dashboards/v1/http/delete_test.go @@ -1,14 +1,10 @@ package http import ( - "context" - "errors" "fmt" "net/http" - "net/http/httptest" "testing" - "github.com/go-chi/chi/v5" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" @@ -16,10 +12,6 @@ import ( ) func TestServeDelete(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - type mockArgs struct { req types.DeleteDashboardRequest err error @@ -28,82 +20,48 @@ func TestServeDelete(t *testing.T) { tests := []struct { name string - uuid string - wantStatus int - + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - uuid: dashboardUUID, - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, - ProfileID: profileID, - }, - }, - }, - { - name: "err_no_user", - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_uuid", - uuid: "invalid-uuid", - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_permission_denied", - uuid: dashboardUUID, - wantStatus: http.StatusForbidden, + name: "ok", mockArgs: &mockArgs{ req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, - ProfileID: profileID, + UUID: dashboardUUID, }, - err: types.ErrPermissionDenied, }, }, { - name: "err_repo_random", - uuid: dashboardUUID, - wantStatus: http.StatusInternalServerError, + name: "err_svc", + wantErr: true, mockArgs: &mockArgs{ req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, - ProfileID: profileID, + UUID: dashboardUUID, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) - req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/dashboards/v1/%s", tt.uuid), http.NoBody) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("uuid", tt.uuid) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Delete(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + DeleteDashboard(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveDelete, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ + Method: http.MethodDelete, + Target: fmt.Sprintf("/dashboards/v1/%s", dashboardUUID), + Handler: withUUID(api.serveDelete, dashboardUUID), + NoResp: true, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/http/get_all.go b/internal/api/dashboards/v1/http/get_all.go index 6380216..49e3023 100644 --- a/internal/api/dashboards/v1/http/get_all.go +++ b/internal/api/dashboards/v1/http/get_all.go @@ -44,16 +44,11 @@ func (a *API) serveGetAll(w http.ResponseWriter, r *http.Request) { }, ) - // check auth and create profile if its doesn't exist - if _, err := a.profiles.GeIDFromContext(ctx); err != nil { - httputil.ProcessError(wr, err) - return - } - req := types.GetAllDashboardsRequest{ Limit: httpReq.Limit, Offset: httpReq.Offset, } + dis, err := a.service.GetAllDashboards(ctx, req) if err != nil { httputil.ProcessError(wr, err) diff --git a/internal/api/dashboards/v1/http/get_all_test.go b/internal/api/dashboards/v1/http/get_all_test.go index f50fdd6..9f62aa5 100644 --- a/internal/api/dashboards/v1/http/get_all_test.go +++ b/internal/api/dashboards/v1/http/get_all_test.go @@ -1,12 +1,7 @@ package http import ( - "context" - "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" "go.uber.org/mock/gomock" @@ -16,15 +11,6 @@ import ( ) func TestServeGetAll(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - limit := 2 - offset := 0 - - formatReqBody := func(limit, offset int) string { - return fmt.Sprintf(`{"limit":%d,"offset":%d}`, limit, offset) - } - type mockArgs struct { req types.GetAllDashboardsRequest resp types.DashboardInfosWithOwner @@ -34,18 +20,21 @@ func TestServeGetAll(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req getAllRequest + want getAllResponse + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - reqBody: formatReqBody(limit, offset), - wantRespBody: `{"dashboards":[{"uuid":"064dc707-02b8-7000-8201-02a7f396738a","name":"dashboard1","owner_name":"user1"},{"uuid":"064dc707-12b9-7000-a238-682b044c908b","name":"dashboard2","owner_name":"user2"}]}`, - wantStatus: http.StatusOK, + name: "ok", + req: getAllRequest{Limit: limit, Offset: offset}, + want: getAllResponse{ + Dashboards: infosWithOwner{ + {info: info{UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, OwnerName: "user1"}, + {info: info{UUID: "064dc707-12b9-7000-a238-682b044c908b", Name: "dashboard2"}, OwnerName: "user2"}, + }, + }, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ Limit: limit, @@ -70,62 +59,39 @@ func TestServeGetAll(t *testing.T) { }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(limit, offset), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_limit", - reqBody: formatReqBody(0, offset), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_invalid_offset", - reqBody: formatReqBody(limit, -10), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_random", - reqBody: formatReqBody(limit, offset), - wantStatus: http.StatusInternalServerError, + name: "err_svc", + req: getAllRequest{Limit: limit, Offset: offset}, + wantErr: true, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ Limit: limit, Offset: offset, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - req := httptest.NewRequest(http.MethodPost, "/dashboards/v1/all", strings.NewReader(tt.reqBody)) - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetAll(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetAllDashboards(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetAll, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAllRequest, getAllResponse]{ + Method: http.MethodPost, + Target: "/dashboards/v1/all", + Req: tt.req, + Handler: api.serveGetAll, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/http/get_by_uuid.go b/internal/api/dashboards/v1/http/get_by_uuid.go index 09bad62..d6a8e23 100644 --- a/internal/api/dashboards/v1/http/get_by_uuid.go +++ b/internal/api/dashboards/v1/http/get_by_uuid.go @@ -32,12 +32,6 @@ func (a *API) serveGetByUUID(w http.ResponseWriter, r *http.Request) { Value: attribute.StringValue(uuid), }) - // check auth and create profile if its doesn't exist - if _, err := a.profiles.GeIDFromContext(ctx); err != nil { - httputil.ProcessError(wr, err) - return - } - d, err := a.service.GetDashboardByUUID(ctx, uuid) if err != nil { httputil.ProcessError(wr, err) diff --git a/internal/api/dashboards/v1/http/get_by_uuid_test.go b/internal/api/dashboards/v1/http/get_by_uuid_test.go index e17b483..da2f63e 100644 --- a/internal/api/dashboards/v1/http/get_by_uuid_test.go +++ b/internal/api/dashboards/v1/http/get_by_uuid_test.go @@ -1,14 +1,10 @@ package http import ( - "context" - "errors" "fmt" "net/http" - "net/http/httptest" "testing" - "github.com/go-chi/chi/v5" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" @@ -16,10 +12,6 @@ import ( ) func TestServeGetByUUID(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - type mockArgs struct { uuid string resp types.Dashboard @@ -29,18 +21,18 @@ func TestServeGetByUUID(t *testing.T) { tests := []struct { name string - uuid string - wantRespBody string - wantStatus int + want dashboard + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - uuid: dashboardUUID, - wantRespBody: `{"name":"dashboard1","meta":"meta1","owner_name":"owner"}`, - wantStatus: http.StatusOK, + name: "ok", + want: dashboard{ + Name: "dashboard1", + Meta: "meta1", + OwnerName: "owner", + }, mockArgs: &mockArgs{ uuid: dashboardUUID, resp: types.Dashboard{ @@ -51,59 +43,34 @@ func TestServeGetByUUID(t *testing.T) { }, }, { - name: "err_no_user", - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_uuid", - uuid: "invalid-uuid", - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_not_found", - uuid: dashboardUUID, - wantStatus: http.StatusNotFound, + name: "err_svc", + wantErr: true, mockArgs: &mockArgs{ uuid: dashboardUUID, - err: types.ErrNotFound, - }, - }, - { - name: "err_repo_random", - uuid: dashboardUUID, - wantStatus: http.StatusInternalServerError, - mockArgs: &mockArgs{ - uuid: dashboardUUID, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) - req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/dashboards/v1/%s", tt.uuid), http.NoBody) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("uuid", tt.uuid) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetByUUID(gomock.Any(), tt.mockArgs.uuid). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetDashboardByUUID(gomock.Any(), tt.mockArgs.uuid). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetByUUID, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, dashboard]{ + Method: http.MethodGet, + Target: fmt.Sprintf("/dashboards/v1/%s", dashboardUUID), + Handler: withUUID(api.serveGetByUUID, dashboardUUID), + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/http/get_my.go b/internal/api/dashboards/v1/http/get_my.go index 66c182f..661e386 100644 --- a/internal/api/dashboards/v1/http/get_my.go +++ b/internal/api/dashboards/v1/http/get_my.go @@ -44,17 +44,11 @@ func (a *API) serveGetMy(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - req := types.GetUserDashboardsRequest{ - ProfileID: profileID, - Limit: httpReq.Limit, - Offset: httpReq.Offset, + Limit: httpReq.Limit, + Offset: httpReq.Offset, } + dis, err := a.service.GetMyDashboards(ctx, req) if err != nil { httputil.ProcessError(wr, err) diff --git a/internal/api/dashboards/v1/http/get_my_test.go b/internal/api/dashboards/v1/http/get_my_test.go index 6965487..b25ef12 100644 --- a/internal/api/dashboards/v1/http/get_my_test.go +++ b/internal/api/dashboards/v1/http/get_my_test.go @@ -1,12 +1,7 @@ package http import ( - "context" - "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" "go.uber.org/mock/gomock" @@ -16,15 +11,6 @@ import ( ) func TestServeGetMy(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - limit := 2 - offset := 0 - - formatReqBody := func(limit, offset int) string { - return fmt.Sprintf(`{"limit":%d,"offset":%d}`, limit, offset) - } - type mockArgs struct { req types.GetUserDashboardsRequest resp types.DashboardInfos @@ -34,23 +20,25 @@ func TestServeGetMy(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req getMyRequest + want getMyResponse + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - reqBody: formatReqBody(limit, offset), - wantRespBody: `{"dashboards":[{"uuid":"064dc707-02b8-7000-8201-02a7f396738a","name":"dashboard1"},{"uuid":"064dc707-12b9-7000-a238-682b044c908b","name":"dashboard2"}]}`, - wantStatus: http.StatusOK, + name: "ok", + req: getMyRequest{Limit: limit, Offset: offset}, + want: getMyResponse{ + Dashboards: infos{ + {UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, + {UUID: "064dc707-12b9-7000-a238-682b044c908b", Name: "dashboard2"}, + }, + }, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - ProfileID: profileID, - Limit: limit, - Offset: offset, + Limit: limit, + Offset: offset, }, resp: types.DashboardInfos{ {UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, @@ -59,63 +47,39 @@ func TestServeGetMy(t *testing.T) { }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(limit, offset), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_limit", - reqBody: formatReqBody(0, offset), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_invalid_offset", - reqBody: formatReqBody(limit, -10), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_random", - reqBody: formatReqBody(limit, offset), - wantStatus: http.StatusInternalServerError, + name: "err_svc", + req: getMyRequest{Limit: limit, Offset: offset}, + wantErr: true, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - ProfileID: profileID, - Limit: limit, - Offset: offset, + Limit: limit, + Offset: offset, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - req := httptest.NewRequest(http.MethodPost, "/dashboards/v1/my", strings.NewReader(tt.reqBody)) - api, mockedRepo := newTestData(t) + api, mockedRepo := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetMy(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedRepo.EXPECT(). + GetMyDashboards(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetMy, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getMyRequest, getMyResponse]{ + Method: http.MethodPost, + Target: "/dashboards/v1/my", + Req: tt.req, + Handler: api.serveGetMy, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/http/search.go b/internal/api/dashboards/v1/http/search.go index a297b69..71e3728 100644 --- a/internal/api/dashboards/v1/http/search.go +++ b/internal/api/dashboards/v1/http/search.go @@ -57,12 +57,6 @@ func (a *API) serveSearch(w http.ResponseWriter, r *http.Request) { span.SetAttributes(spanAttributes...) - // check auth and create profile if its doesn't exist - if _, err := a.profiles.GeIDFromContext(ctx); err != nil { - httputil.ProcessError(wr, err) - return - } - req := types.SearchDashboardsRequest{ Query: httpReq.Query, Limit: httpReq.Limit, diff --git a/internal/api/dashboards/v1/http/search_test.go b/internal/api/dashboards/v1/http/search_test.go index a47becb..630b303 100644 --- a/internal/api/dashboards/v1/http/search_test.go +++ b/internal/api/dashboards/v1/http/search_test.go @@ -1,12 +1,7 @@ package http import ( - "context" - "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" "go.uber.org/mock/gomock" @@ -16,29 +11,6 @@ import ( ) func TestServeSearch(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - query := "test" - limit := 2 - offset := 0 - filter := &types.SearchDashboardsFilter{ - OwnerName: &userName, - } - - formatReqBody := func(query string, limit, offset int, filter *types.SearchDashboardsFilter) string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf(`{"query":%q,"limit":%d,"offset":%d`, query, limit, offset)) - if filter != nil { - sb.WriteString(`,"filter":{`) - if filter.OwnerName != nil { - sb.WriteString(fmt.Sprintf(`"owner_name":%q`, *filter.OwnerName)) - } - sb.WriteString("}") - } - sb.WriteString("}") - return sb.String() - } - type mockArgs struct { req types.SearchDashboardsRequest resp types.DashboardInfosWithOwner @@ -48,18 +20,21 @@ func TestServeSearch(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req searchRequest + want searchResponse + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - reqBody: formatReqBody(query, limit, offset, nil), - wantRespBody: `{"dashboards":[{"uuid":"064dc707-02b8-7000-8201-02a7f396738a","name":"my test dashboard","owner_name":"user1"},{"uuid":"064dc707-12b9-7000-a238-682b044c908b","name":"tested","owner_name":"user2"}]}`, - wantStatus: http.StatusOK, + name: "ok", + req: searchRequest{Query: query, Limit: limit, Offset: offset}, + want: searchResponse{ + Dashboards: infosWithOwner{ + {info: info{UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "my test dashboard"}, OwnerName: "user1"}, + {info: info{UUID: "064dc707-12b9-7000-a238-682b044c908b", Name: "tested"}, OwnerName: "user2"}, + }, + }, mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: query, @@ -85,16 +60,26 @@ func TestServeSearch(t *testing.T) { }, }, { - name: "success_with_filter", - reqBody: formatReqBody(query, limit, offset, filter), - wantRespBody: fmt.Sprintf(`{"dashboards":[{"uuid":"064dc707-02b8-7000-8201-02a7f396738a","name":"my test dashboard","owner_name":%q}]}`, userName), - wantStatus: http.StatusOK, + name: "ok_filter", + req: searchRequest{ + Query: query, + Limit: limit, + Offset: offset, + Filter: &searchFilter{OwnerName: &userName}, + }, + want: searchResponse{ + Dashboards: infosWithOwner{ + {info: info{UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "my test dashboard"}, OwnerName: userName}, + }, + }, mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: query, Limit: limit, Offset: offset, - Filter: filter, + Filter: &types.SearchDashboardsFilter{ + OwnerName: &userName, + }, }, resp: types.DashboardInfosWithOwner{ { @@ -108,63 +93,40 @@ func TestServeSearch(t *testing.T) { }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(query, limit, offset, nil), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_limit", - reqBody: formatReqBody(query, 0, offset, nil), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_invalid_offset", - reqBody: formatReqBody(query, limit, -10, nil), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_random", - reqBody: formatReqBody(query, limit, offset, nil), - wantStatus: http.StatusInternalServerError, + name: "err_svc", + req: searchRequest{Query: query, Limit: limit, Offset: offset}, + wantErr: true, mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: query, Limit: limit, Offset: offset, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - req := httptest.NewRequest(http.MethodPost, "/dashboards/v1/search", strings.NewReader(tt.reqBody)) - api, mockedRepo := newTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Search(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + SearchDashboards(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveSearch, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[searchRequest, searchResponse]{ + Method: http.MethodPost, + Target: "/dashboards/v1/search", + Req: tt.req, + Handler: api.serveSearch, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/http/test_data.go b/internal/api/dashboards/v1/http/test_data.go index e65a669..6f3861c 100644 --- a/internal/api/dashboards/v1/http/test_data.go +++ b/internal/api/dashboards/v1/http/test_data.go @@ -1,18 +1,39 @@ package http import ( + "context" "errors" + "net/http" "testing" - "github.com/ozontech/seq-ui/internal/api/dashboards/v1/test" - repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + "github.com/go-chi/chi/v5" + "go.uber.org/mock/gomock" + + mock "github.com/ozontech/seq-ui/internal/pkg/service/dashboards/mock" ) var ( errSomethingWrong = errors.New("something happened wrong") + userName = "unnamed" + dashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" + dashboardName = "my_dashboard" + dashboardMeta = "my_meta" + query = "test-query" + limit = 2 + offset = 0 ) -func newTestData(t *testing.T) (*API, *repo_mock.MockDashboards) { - mock, s, p := test.NewTestData(t) - return New(s, p), mock +func setupAPI(t *testing.T) (*API, *mock.MockService) { + ctrl := gomock.NewController(t) + mockedSvc := mock.NewMockService(ctrl) + return New(mockedSvc), mockedSvc +} + +func withUUID(h http.HandlerFunc, uuid string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + rCtx := chi.NewRouteContext() + rCtx.URLParams.Add("uuid", uuid) + r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rCtx)) + h(w, r) + } } diff --git a/internal/api/dashboards/v1/http/update.go b/internal/api/dashboards/v1/http/update.go index 8979ba5..5f23b4d 100644 --- a/internal/api/dashboards/v1/http/update.go +++ b/internal/api/dashboards/v1/http/update.go @@ -48,19 +48,13 @@ func (a *API) serveUpdate(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - req := types.UpdateDashboardRequest{ - UUID: uuid, - ProfileID: profileID, - Name: httpReq.Name, - Meta: httpReq.Meta, + UUID: uuid, + Name: httpReq.Name, + Meta: httpReq.Meta, } - err = a.service.UpdateDashboard(ctx, req) + + err := a.service.UpdateDashboard(ctx, req) if err != nil { httputil.ProcessError(wr, err) return diff --git a/internal/api/dashboards/v1/http/update_test.go b/internal/api/dashboards/v1/http/update_test.go index b9be7f4..96ec57b 100644 --- a/internal/api/dashboards/v1/http/update_test.go +++ b/internal/api/dashboards/v1/http/update_test.go @@ -1,15 +1,10 @@ package http import ( - "context" - "errors" "fmt" "net/http" - "net/http/httptest" - "strings" "testing" - "github.com/go-chi/chi/v5" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" @@ -17,28 +12,6 @@ import ( ) func TestServeUpdate(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName := "my_dashboard" - dashboardMeta := "my_meta" - - formatReqBody := func(name, meta string) string { - var sb strings.Builder - sb.WriteString("{") - if name != "" { - sb.WriteString(fmt.Sprintf(`"name":%q`, name)) - } - if meta != "" { - if name != "" { - sb.WriteString(",") - } - sb.WriteString(fmt.Sprintf(`"meta":%q`, meta)) - } - sb.WriteString("}") - return sb.String() - } - type mockArgs struct { req types.UpdateDashboardRequest err error @@ -47,147 +20,55 @@ func TestServeUpdate(t *testing.T) { tests := []struct { name string - uuid string - reqBody string - wantStatus int + req updateRequest + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success_all", - uuid: dashboardUUID, - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - }, - }, - { - name: "success_only_name", - uuid: dashboardUUID, - reqBody: formatReqBody(dashboardName, ""), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - }, - }, - }, - { - name: "success_only_meta", - uuid: dashboardUUID, - reqBody: formatReqBody("", dashboardMeta), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Meta: &dashboardMeta, - }, - }, - }, - { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_uuid", - uuid: "invalid-uuid", - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_empty_request", - uuid: dashboardUUID, - reqBody: `{}`, - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_not_found", - uuid: dashboardUUID, - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusNotFound, + name: "ok", + req: updateRequest{Name: &dashboardName, Meta: &dashboardMeta}, mockArgs: &mockArgs{ req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + UUID: dashboardUUID, + Name: &dashboardName, + Meta: &dashboardMeta, }, - err: types.ErrNotFound, }, }, { - name: "err_repo_permission_denied", - uuid: dashboardUUID, - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusForbidden, + name: "err_svc", + req: updateRequest{Name: &dashboardName, Meta: &dashboardMeta}, + wantErr: true, mockArgs: &mockArgs{ req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + UUID: dashboardUUID, + Name: &dashboardName, + Meta: &dashboardMeta, }, - err: types.ErrPermissionDenied, - }, - }, - { - name: "err_repo_random", - uuid: dashboardUUID, - reqBody: formatReqBody(dashboardName, dashboardMeta), - wantStatus: http.StatusInternalServerError, - mockArgs: &mockArgs{ - req: types.UpdateDashboardRequest{ - ProfileID: profileID, - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, - }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newTestData(t) - req := httptest.NewRequest(http.MethodPatch, fmt.Sprintf("/dashboards/v1/%s", tt.uuid), strings.NewReader(tt.reqBody)) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("uuid", tt.uuid) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Update(gomock.Any(), tt.mockArgs.req). + mockedSvc.EXPECT().UpdateDashboard(gomock.Any(), tt.mockArgs.req). Return(tt.mockArgs.err).Times(1) } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) - } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveUpdate, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[updateRequest, struct{}]{ + Method: http.MethodPatch, + Target: fmt.Sprintf("/dashboards/v1/%s", dashboardUUID), + Req: tt.req, + Handler: withUUID(api.serveUpdate, dashboardUUID), + NoResp: true, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/dashboards/v1/test/data.go b/internal/api/dashboards/v1/test/data.go deleted file mode 100644 index 5ae9e80..0000000 --- a/internal/api/dashboards/v1/test/data.go +++ /dev/null @@ -1,23 +0,0 @@ -package test - -import ( - "testing" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/profiles" - repo "github.com/ozontech/seq-ui/internal/pkg/repository" - repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" - "github.com/ozontech/seq-ui/internal/pkg/service" -) - -func NewTestData(t *testing.T) (*repo_mock.MockDashboards, service.Service, *profiles.Profiles) { - ctl := gomock.NewController(t) - mockedRepo := repo_mock.NewMockDashboards(ctl) - r := &repo.Repository{ - Dashboards: mockedRepo, - } - s := service.New(r) - p := profiles.New(s) - return mockedRepo, s, p -} diff --git a/internal/api/massexport/v1/grpc/cancel_test.go b/internal/api/massexport/v1/grpc/cancel_test.go new file mode 100644 index 0000000..42e61e5 --- /dev/null +++ b/internal/api/massexport/v1/grpc/cancel_test.go @@ -0,0 +1,68 @@ +package grpc + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" +) + +func TestCancel(t *testing.T) { + type mockArgs struct { + err error + } + + tests := []struct { + name string + + req *massexport_v1.CancelRequest + want *massexport_v1.CancelResponse + wantCode codes.Code + + mockArgs *mockArgs + }{ + { + name: "ok", + req: &massexport_v1.CancelRequest{SessionId: sessionID}, + want: &massexport_v1.CancelResponse{}, + mockArgs: &mockArgs{}, + }, + { + name: "svc_err", + req: &massexport_v1.CancelRequest{SessionId: sessionID}, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + CancelExport(gomock.Any(), tt.req.GetSessionId()). + Return(tt.mockArgs.err). + Times(1) + } + + got, err := api.Cancel(context.Background(), tt.req) + + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + + require.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/massexport/v1/grpc/check_test.go b/internal/api/massexport/v1/grpc/check_test.go new file mode 100644 index 0000000..e5cabfe --- /dev/null +++ b/internal/api/massexport/v1/grpc/check_test.go @@ -0,0 +1,80 @@ +package grpc + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/ozontech/seq-ui/internal/app/types" + massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" +) + +func TestCheck(t *testing.T) { + type mockArgs struct { + resp types.ExportInfo + err error + } + + tests := []struct { + name string + + req *massexport_v1.CheckRequest + want *massexport_v1.CheckResponse + wantCode codes.Code + + mockArgs *mockArgs + }{ + { + name: "ok", + req: &massexport_v1.CheckRequest{SessionId: sessionID}, + want: convertExportInfo(types.ExportInfo{ + ID: sessionID, + UserID: userID, + Status: types.ExportStatusFinish, + }), + mockArgs: &mockArgs{ + resp: types.ExportInfo{ + ID: sessionID, + UserID: userID, + Status: types.ExportStatusFinish, + }, + }, + }, + { + name: "err_svc", + req: &massexport_v1.CheckRequest{SessionId: sessionID}, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + CheckExport(gomock.Any(), tt.req.GetSessionId()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + } + + got, err := api.Check(context.Background(), tt.req) + + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + + require.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/massexport/v1/grpc/get_all_test.go b/internal/api/massexport/v1/grpc/get_all_test.go new file mode 100644 index 0000000..0c7ac6e --- /dev/null +++ b/internal/api/massexport/v1/grpc/get_all_test.go @@ -0,0 +1,86 @@ +package grpc + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/ozontech/seq-ui/internal/app/types" + massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" +) + +func TestGetAll(t *testing.T) { + type mockArgs struct { + resp []types.ExportInfo + err error + } + + tests := []struct { + name string + + req *massexport_v1.GetAllRequest + want *massexport_v1.GetAllResponse + wantCode codes.Code + + mockArgs *mockArgs + }{ + { + name: "ok", + req: &massexport_v1.GetAllRequest{}, + want: &massexport_v1.GetAllResponse{ + Exports: []*massexport_v1.CheckResponse{ + convertExportInfo(types.ExportInfo{ + ID: sessionID, + UserID: userID, + Status: types.ExportStatusFinish, + }), + }, + }, + mockArgs: &mockArgs{ + resp: []types.ExportInfo{ + { + ID: sessionID, + UserID: userID, + Status: types.ExportStatusFinish, + }, + }, + }, + }, + { + name: "err_svc", + req: &massexport_v1.GetAllRequest{}, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + GetAll(gomock.Any()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + } + + got, err := api.GetAll(context.Background(), tt.req) + + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + + require.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/massexport/v1/grpc/restore_test.go b/internal/api/massexport/v1/grpc/restore_test.go new file mode 100644 index 0000000..594d78b --- /dev/null +++ b/internal/api/massexport/v1/grpc/restore_test.go @@ -0,0 +1,64 @@ +package grpc + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" +) + +func TestRestore(t *testing.T) { + type mockArgs struct { + err error + } + + tests := []struct { + name string + + req *massexport_v1.RestoreRequest + wantCode codes.Code + + mockArgs *mockArgs + }{ + { + name: "ok", + req: &massexport_v1.RestoreRequest{SessionId: sessionID}, + mockArgs: &mockArgs{}, + }, + { + name: "err_svc", + req: &massexport_v1.RestoreRequest{SessionId: sessionID}, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + RestoreExport(gomock.Any(), tt.req.GetSessionId()). + Return(tt.mockArgs.err). + Times(1) + } + + _, err := api.Restore(context.Background(), tt.req) + + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + }) + } +} diff --git a/internal/api/massexport/v1/grpc/start_test.go b/internal/api/massexport/v1/grpc/start_test.go new file mode 100644 index 0000000..b4e6346 --- /dev/null +++ b/internal/api/massexport/v1/grpc/start_test.go @@ -0,0 +1,122 @@ +package grpc + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/ozontech/seq-ui/internal/app/types" + massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" +) + +func TestStart(t *testing.T) { + type mockArgs struct { + resp types.StartExportResponse + err error + } + + tests := []struct { + name string + + req *massexport_v1.StartRequest + want *massexport_v1.StartResponse + wantCode codes.Code + + mockArgs *mockArgs + }{ + { + name: "ok", + req: &massexport_v1.StartRequest{ + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(to), + Window: testWindow, + Name: testName, + }, + want: &massexport_v1.StartResponse{ + SessionId: sessionID, + }, + mockArgs: &mockArgs{ + resp: types.StartExportResponse{ + SessionID: sessionID, + }, + }, + }, + { + name: "err_empty_name", + req: &massexport_v1.StartRequest{ + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(to), + Window: testWindow, + }, + wantCode: codes.InvalidArgument, + }, + { + name: "err_invalid_window", + req: &massexport_v1.StartRequest{ + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(to), + Window: "invalid", + Name: testName, + }, + wantCode: codes.InvalidArgument, + }, + { + name: "err_window_larger_than_interval", + req: &massexport_v1.StartRequest{ + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(from.Add(5 * time.Second)), + Window: testWindow, + Name: testName, + }, + wantCode: codes.InvalidArgument, + }, + { + name: "err_svc", + req: &massexport_v1.StartRequest{ + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(to), + Window: testWindow, + Name: testName, + }, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + StartExport(gomock.Any(), gomock.Any()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + } + + got, err := api.Start(context.Background(), tt.req) + + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + + require.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/massexport/v1/grpc/test_data.go b/internal/api/massexport/v1/grpc/test_data.go new file mode 100644 index 0000000..d319e91 --- /dev/null +++ b/internal/api/massexport/v1/grpc/test_data.go @@ -0,0 +1,28 @@ +package grpc + +import ( + "errors" + "testing" + "time" + + "go.uber.org/mock/gomock" + + mock_massexport "github.com/ozontech/seq-ui/internal/pkg/service/massexport/mock" +) + +var ( + errSomethingWrong = errors.New("something happened wrong") + query = "message:error" + testName = "test-export" + testWindow = "10s" + sessionID = "test-session-id" + userID = "test-user" + from = time.Now() + to = from.Add(10 * time.Minute) +) + +func setupAPI(t *testing.T) (*API, *mock_massexport.MockService) { + ctrl := gomock.NewController(t) + svcMock := mock_massexport.NewMockService(ctrl) + return New(svcMock), svcMock +} diff --git a/internal/api/massexport/v1/http/cancel_test.go b/internal/api/massexport/v1/http/cancel_test.go new file mode 100644 index 0000000..43b51e2 --- /dev/null +++ b/internal/api/massexport/v1/http/cancel_test.go @@ -0,0 +1,63 @@ +package http + +import ( + "net/http" + "testing" + + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/api/httputil" +) + +func TestServeCancel(t *testing.T) { + type mockArgs struct { + err error + } + + tests := []struct { + name string + + req cancelRequest + wantErr bool + + mockArgs *mockArgs + }{ + { + name: "ok", + req: cancelRequest{SessionID: sessionID}, + mockArgs: &mockArgs{}, + }, + { + name: "err_svc", + req: cancelRequest{SessionID: sessionID}, + wantErr: true, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + CancelExport(gomock.Any(), tt.req.SessionID). + Return(tt.mockArgs.err). + Times(1) + } + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[cancelRequest, struct{}]{ + Method: http.MethodPost, + Target: "/massexport/v1/cancel", + Req: tt.req, + Handler: api.serveCancel, + WantErr: tt.wantErr, + NoResp: true, + }) + }) + } +} diff --git a/internal/api/massexport/v1/http/check_test.go b/internal/api/massexport/v1/http/check_test.go new file mode 100644 index 0000000..7450c9d --- /dev/null +++ b/internal/api/massexport/v1/http/check_test.go @@ -0,0 +1,83 @@ +package http + +import ( + "net/http" + "testing" + "time" + + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/api/httputil" + "github.com/ozontech/seq-ui/internal/app/types" +) + +func TestServeCheck(t *testing.T) { + type mockArgs struct { + resp types.ExportInfo + err error + } + + tests := []struct { + name string + + req checkRequest + want checkResponse + wantErr bool + + mockArgs *mockArgs + }{ + { + name: "ok", + req: checkRequest{SessionID: sessionID}, + mockArgs: &mockArgs{ + resp: types.ExportInfo{ + ID: sessionID, + UserID: userID, + Status: types.ExportStatusFinish, + StartedAt: from, + FinishedAt: to, + }, + }, + want: checkResponse{ + ID: sessionID, + UserID: userID, + Status: exportStatusFinish, + StartedAt: from, + FinishedAt: to, + Duration: (10 * time.Minute).String(), + }, + }, + { + name: "err_svc", + req: checkRequest{SessionID: sessionID}, + wantErr: true, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + CheckExport(gomock.Any(), tt.req.SessionID). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + } + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[checkRequest, checkResponse]{ + Method: http.MethodPost, + Target: "/massexport/v1/check", + Req: tt.req, + Handler: api.serveCheck, + Want: tt.want, + WantErr: tt.wantErr, + }) + }) + } +} diff --git a/internal/api/massexport/v1/http/get_all_test.go b/internal/api/massexport/v1/http/get_all_test.go new file mode 100644 index 0000000..0880334 --- /dev/null +++ b/internal/api/massexport/v1/http/get_all_test.go @@ -0,0 +1,83 @@ +package http + +import ( + "net/http" + "testing" + "time" + + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/api/httputil" + "github.com/ozontech/seq-ui/internal/app/types" +) + +func TestServeGetAll(t *testing.T) { + type mockArgs struct { + resp []types.ExportInfo + err error + } + + tests := []struct { + name string + + want getAllResponse + wantErr bool + + mockArgs mockArgs + }{ + { + name: "ok", + mockArgs: mockArgs{ + resp: []types.ExportInfo{ + { + ID: sessionID, + UserID: userID, + Status: types.ExportStatusFinish, + StartedAt: from, + FinishedAt: to, + }, + }, + }, + want: getAllResponse{ + Exports: []checkResponse{ + { + ID: sessionID, + UserID: userID, + Status: exportStatusFinish, + StartedAt: from, + FinishedAt: to, + Duration: (10 * time.Minute).String(), + }, + }, + }, + }, + { + name: "err_svc", + wantErr: true, + mockArgs: mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + svcMock.EXPECT(). + GetAll(gomock.Any()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getAllResponse]{ + Method: http.MethodGet, + Target: "/massexport/v1/jobs", + Handler: api.serveJobs, + Want: tt.want, + WantErr: tt.wantErr, + }) + }) + } +} diff --git a/internal/api/massexport/v1/http/restore_test.go b/internal/api/massexport/v1/http/restore_test.go new file mode 100644 index 0000000..016ec53 --- /dev/null +++ b/internal/api/massexport/v1/http/restore_test.go @@ -0,0 +1,63 @@ +package http + +import ( + "net/http" + "testing" + + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/api/httputil" +) + +func TestServeRestore(t *testing.T) { + type mockArgs struct { + err error + } + + tests := []struct { + name string + + req restoreRequest + wantErr bool + + mockArgs *mockArgs + }{ + { + name: "ok", + req: restoreRequest{SessionID: sessionID}, + mockArgs: &mockArgs{}, + }, + { + name: "err_svc", + req: restoreRequest{SessionID: sessionID}, + wantErr: true, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + RestoreExport(gomock.Any(), tt.req.SessionID). + Return(tt.mockArgs.err). + Times(1) + } + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[restoreRequest, struct{}]{ + Method: http.MethodPost, + Target: "/massexport/v1/restore", + Req: tt.req, + Handler: api.serveRestore, + WantErr: tt.wantErr, + NoResp: true, + }) + }) + } +} diff --git a/internal/api/massexport/v1/http/start_test.go b/internal/api/massexport/v1/http/start_test.go new file mode 100644 index 0000000..7467a10 --- /dev/null +++ b/internal/api/massexport/v1/http/start_test.go @@ -0,0 +1,118 @@ +package http + +import ( + "net/http" + "testing" + "time" + + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/api/httputil" + "github.com/ozontech/seq-ui/internal/app/types" +) + +func TestServeStart(t *testing.T) { + type mockArgs struct { + resp types.StartExportResponse + err error + } + + tests := []struct { + name string + + req startRequest + want startResponse + wantErr bool + + mockArgs *mockArgs + }{ + { + name: "ok", + req: startRequest{ + Query: query, + From: from, + To: to, + Window: window, + Name: testName, + }, + want: startResponse{ + SessionID: sessionID, + }, + mockArgs: &mockArgs{ + resp: types.StartExportResponse{ + SessionID: sessionID, + }, + }, + }, + { + name: "err_empty_name", + req: startRequest{ + Query: query, + From: from, + To: to, + Window: window, + }, + wantErr: true, + }, + { + name: "err_invalid_window", + req: startRequest{ + Query: query, + From: from, + To: to, + Window: "invalid", + Name: testName, + }, + wantErr: true, + }, + { + name: "err_window_larger_than_interval", + req: startRequest{ + Query: query, + From: from, + To: from.Add(5 * time.Second), + Window: window, + Name: testName, + }, + wantErr: true, + }, + { + name: "err_svc", + req: startRequest{ + Query: query, + From: from, + To: to, + Window: window, + Name: testName, + }, + wantErr: true, + mockArgs: &mockArgs{ + err: errSomethingWrong, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + api, svcMock := setupAPI(t) + + if tt.mockArgs != nil { + svcMock.EXPECT(). + StartExport(gomock.Any(), gomock.Any()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + } + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[startRequest, startResponse]{ + Method: http.MethodPost, + Target: "/massexport/v1/start", + Req: tt.req, + Handler: api.serveStart, + Want: tt.want, + WantErr: tt.wantErr, + }) + }) + } +} diff --git a/internal/api/massexport/v1/http/test_data.go b/internal/api/massexport/v1/http/test_data.go new file mode 100644 index 0000000..74788a8 --- /dev/null +++ b/internal/api/massexport/v1/http/test_data.go @@ -0,0 +1,28 @@ +package http + +import ( + "errors" + "testing" + "time" + + "go.uber.org/mock/gomock" + + mock_massexport "github.com/ozontech/seq-ui/internal/pkg/service/massexport/mock" +) + +var ( + errSomethingWrong = errors.New("something happened wrong") + query = "message:error" + testName = "test-export" + window = "10s" + sessionID = "test-session-id" + userID = "test-user" + from = time.Now() + to = from.Add(10 * time.Minute) +) + +func setupAPI(t *testing.T) (*API, *mock_massexport.MockService) { + ctrl := gomock.NewController(t) + svcMock := mock_massexport.NewMockService(ctrl) + return New(svcMock), svcMock +} diff --git a/internal/api/seqapi/v1/grpc/aggregation_test.go b/internal/api/seqapi/v1/grpc/aggregation_test.go index d2b40ef..1bfd43b 100644 --- a/internal/api/seqapi/v1/grpc/aggregation_test.go +++ b/internal/api/seqapi/v1/grpc/aggregation_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "testing" - "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -18,15 +17,11 @@ import ( ) func TestGetAggregation(t *testing.T) { - query := "message:error" - from := time.Now() - to := from.Add(time.Second) - tests := []struct { name string req *seqapi.GetAggregationRequest - resp *seqapi.GetAggregationResponse + want *seqapi.GetAggregationResponse apiErr bool clientErr error @@ -44,7 +39,7 @@ func TestGetAggregation(t *testing.T) { {Field: "test2"}, }, }, - resp: &seqapi.GetAggregationResponse{ + want: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, nil), Error: &seqapi.Error{ Code: seqapi.ErrorCode_ERROR_CODE_NO, @@ -90,8 +85,8 @@ func TestGetAggregation(t *testing.T) { clientErr: errors.New("client error"), }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -103,39 +98,35 @@ func TestGetAggregation(t *testing.T) { ctrl := gomock.NewController(t) seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetAggregation(gomock.Any(), proto.Clone(tt.req)). - Return(proto.Clone(tt.resp), tt.clientErr).Times(1) + seqDbMock.EXPECT(). + GetAggregation(gomock.Any(), proto.Clone(tt.req)). + Return(proto.Clone(tt.want), tt.clientErr). + Times(1) seqData.Mocks.SeqDB = seqDbMock } - s := initTestAPI(seqData) + api := setupAPI(seqData) - resp, err := s.GetAggregation(context.Background(), tt.req) + resp, err := api.GetAggregation(context.Background(), tt.req) if tt.apiErr { require.True(t, err != nil) return } require.Equal(t, tt.clientErr, err) - require.True(t, proto.Equal(resp, tt.resp)) + require.True(t, proto.Equal(resp, tt.want)) }) } } func TestGetAggregationWithNormalization(t *testing.T) { - query := "message:error" - from := time.Now() - to := from.Add(time.Second) - targetBucketRate := "3s" - interval := "2s" - tests := []struct { name string - req *seqapi.GetAggregationRequest - resp *seqapi.GetAggregationResponse - normalized_resp *seqapi.GetAggregationResponse + req *seqapi.GetAggregationRequest + want *seqapi.GetAggregationResponse + wantNormalized *seqapi.GetAggregationResponse apiErr bool clientErr error @@ -153,7 +144,7 @@ func TestGetAggregationWithNormalization(t *testing.T) { {Field: "test2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, }, }, - resp: &seqapi.GetAggregationResponse{ + want: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ Values: []float64{ 1, @@ -165,7 +156,7 @@ func TestGetAggregationWithNormalization(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - normalized_resp: &seqapi.GetAggregationResponse{ + wantNormalized: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ Values: []float64{ 1, @@ -194,7 +185,7 @@ func TestGetAggregationWithNormalization(t *testing.T) { {Field: "test2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval, TargetBucketRate: &targetBucketRate}, }, }, - resp: &seqapi.GetAggregationResponse{ + want: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ TargetBucketRate: targetBucketRate, Values: []float64{ @@ -207,7 +198,7 @@ func TestGetAggregationWithNormalization(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - normalized_resp: &seqapi.GetAggregationResponse{ + wantNormalized: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ TargetBucketRate: targetBucketRate, Values: []float64{ @@ -227,8 +218,8 @@ func TestGetAggregationWithNormalization(t *testing.T) { }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -241,21 +232,21 @@ func TestGetAggregationWithNormalization(t *testing.T) { seqDbMock := mock_seqdb.NewMockClient(ctrl) seqDbMock.EXPECT().GetAggregation(gomock.Any(), proto.Clone(tt.req)). - Return(proto.Clone(tt.resp), tt.clientErr).Times(1) + Return(proto.Clone(tt.want), tt.clientErr).Times(1) seqData.Mocks.SeqDB = seqDbMock } - s := initTestAPI(seqData) + api := setupAPI(seqData) - resp, err := s.GetAggregation(context.Background(), tt.req) + resp, err := api.GetAggregation(context.Background(), tt.req) if tt.apiErr { require.True(t, err != nil) return } require.Equal(t, tt.clientErr, err) - require.True(t, proto.Equal(resp, tt.normalized_resp)) + require.True(t, proto.Equal(resp, tt.wantNormalized)) }) } } diff --git a/internal/api/seqapi/v1/grpc/api.go b/internal/api/seqapi/v1/grpc/api.go index 44d66a1..da9a784 100644 --- a/internal/api/seqapi/v1/grpc/api.go +++ b/internal/api/seqapi/v1/grpc/api.go @@ -10,7 +10,6 @@ import ( "go.uber.org/zap" "google.golang.org/grpc/metadata" - "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/app/config" "github.com/ozontech/seq-ui/internal/app/types" "github.com/ozontech/seq-ui/internal/pkg/cache" @@ -39,8 +38,7 @@ type API struct { inmemWithRedisCache cache.Cache redisCache cache.Cache nowFn func() time.Time - asyncSearches *asyncsearches.Service - profiles *profiles.Profiles + asyncSearches asyncsearches.Service envsResponse *seqapi.GetEnvsResponse } @@ -49,8 +47,7 @@ func New( seqDBСlients map[string]seqdb.Client, inmemWithRedisCache cache.Cache, redisCache cache.Cache, - asyncSearches *asyncsearches.Service, - p *profiles.Profiles, + asyncSearches asyncsearches.Service, ) *API { var globalfCache *fieldsCache if cfg.FieldsCacheTTL > 0 { @@ -121,7 +118,6 @@ func New( redisCache: redisCache, nowFn: time.Now, asyncSearches: asyncSearches, - profiles: p, envsResponse: parseEnvs(cfg), } } diff --git a/internal/api/seqapi/v1/grpc/cancel_async_search.go b/internal/api/seqapi/v1/grpc/cancel_async_search.go index e54f926..2506f36 100644 --- a/internal/api/seqapi/v1/grpc/cancel_async_search.go +++ b/internal/api/seqapi/v1/grpc/cancel_async_search.go @@ -14,10 +14,7 @@ import ( "github.com/ozontech/seq-ui/tracing" ) -func (a *API) CancelAsyncSearch( - ctx context.Context, - req *seqapi.CancelAsyncSearchRequest, -) (*seqapi.CancelAsyncSearchResponse, error) { +func (a *API) CancelAsyncSearch(ctx context.Context, req *seqapi.CancelAsyncSearchRequest) (*seqapi.CancelAsyncSearchResponse, error) { if a.asyncSearches == nil { return nil, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()) } @@ -36,12 +33,7 @@ func (a *API) CancelAsyncSearch( }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - - resp, err := a.asyncSearches.CancelAsyncSearch(ctx, profileID, req) + resp, err := a.asyncSearches.CancelAsyncSearch(ctx, req) if err != nil { return nil, grpcutil.ProcessError(err) } diff --git a/internal/api/seqapi/v1/grpc/cancel_async_search_test.go b/internal/api/seqapi/v1/grpc/cancel_async_search_test.go index 610cd92..83e4013 100644 --- a/internal/api/seqapi/v1/grpc/cancel_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/cancel_async_search_test.go @@ -8,99 +8,64 @@ import ( "go.uber.org/mock/gomock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) -func TestServeCancelAsyncSearch(t *testing.T) { - const ( - mockSearchID1 = "69e4a4a6-0922-43bd-952d-060a86c2b622" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - mockProfileID1 = 1 - mockProfileID2 = 2 - ) - +func TestCancelAsyncSearch(t *testing.T) { type mockArgs struct { - userName string - - profilesReq *types.GetOrCreateUserProfileRequest - profilesResp *types.UserProfile - profilesErr error - - repoResp *types.AsyncSearchInfo - repoErr error + req *seqapi.CancelAsyncSearchRequest + resp *seqapi.CancelAsyncSearchResponse + err error } tests := []struct { name string - req *seqapi.CancelAsyncSearchRequest - resp *seqapi.CancelAsyncSearchResponse - err error + req *seqapi.CancelAsyncSearchRequest + want *seqapi.CancelAsyncSearchResponse + wantCode codes.Code mockArgs *mockArgs }{ { name: "ok", req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID1, + SearchId: mockSearchID, }, - resp: &seqapi.CancelAsyncSearchResponse{}, + want: &seqapi.CancelAsyncSearchResponse{}, mockArgs: &mockArgs{ - userName: mockUserName1, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, + req: &seqapi.CancelAsyncSearchRequest{ + SearchId: mockSearchID, }, + resp: &seqapi.CancelAsyncSearchResponse{}, }, }, { - name: "err_permission_denied", + name: "invalid_id", req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID1, - }, - mockArgs: &mockArgs{ - userName: mockUserName1, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID2, - OwnerName: mockUserName2, - }, + SearchId: "some_invalid_id", }, - err: status.Error(codes.PermissionDenied, "permission denied: cancel async search"), + wantCode: codes.InvalidArgument, }, { - name: "invalid id", + name: "err_svc", req: &seqapi.CancelAsyncSearchRequest{ - SearchId: "some_invalid_id", + SearchId: mockSearchID, }, + wantCode: codes.Internal, mockArgs: &mockArgs{ - userName: mockUserName1, + req: &seqapi.CancelAsyncSearchRequest{ + SearchId: mockSearchID, + }, + err: errSomethingWrong, }, - err: status.Error(codes.InvalidArgument, "invalid search_id"), }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -110,48 +75,30 @@ func TestServeCancelAsyncSearch(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) - if tt.err == nil { - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().CancelAsyncSearch(gomock.Any(), tt.req). - Return(tt.resp, nil).Times(1) - seqData.Mocks.SeqDB = seqDbMock - } - - if tt.mockArgs.profilesResp != nil { - profilesRepoMock := mock_repo.NewMockUserProfiles(ctrl) - profilesRepoMock.EXPECT().GetOrCreate(gomock.Any(), *tt.mockArgs.profilesReq). - Return(*tt.mockArgs.profilesResp, tt.mockArgs.profilesErr).Times(1) - seqData.Mocks.ProfilesRepo = profilesRepoMock - } - - if tt.mockArgs.repoResp != nil { - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchById(gomock.Any(), tt.req.SearchId). - Return(*tt.mockArgs.repoResp, tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock - } - } + svcMock := mock_asyncsearches.NewMockService(ctrl) + svcMock.EXPECT(). + CancelAsyncSearch(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) - api := initTestAPIWithAsyncSearches(seqData) + seqData.Mocks.AsyncSearchesSvc = svcMock + } - ctx := context.Background() - ctx = context.WithValue(ctx, types.UserKey{}, tt.mockArgs.userName) + api := setupAPIWithAsyncSearches(seqData) + got, err := api.CancelAsyncSearch(context.Background(), tt.req) - resp, err := api.CancelAsyncSearch(ctx, tt.req) - if tt.err == nil { - require.NoError(t, err) - require.True(t, proto.Equal(tt.resp, resp)) - } else { - require.Error(t, err) - require.Equal(t, tt.err, err) + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return } + require.Equal(t, tt.want, got) }) } } -func TestServeCancelAsyncSearch_Disabled(t *testing.T) { +func TestCancelAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) + api := setupAPI(seqData) _, err := api.CancelAsyncSearch(context.Background(), &seqapi.CancelAsyncSearchRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/cluster_status_test.go b/internal/api/seqapi/v1/grpc/cluster_status_test.go index 8dfb5c3..52dbe86 100644 --- a/internal/api/seqapi/v1/grpc/cluster_status_test.go +++ b/internal/api/seqapi/v1/grpc/cluster_status_test.go @@ -2,34 +2,38 @@ package grpc import ( "context" - "errors" "testing" "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" - "github.com/ozontech/seq-ui/internal/app/config" mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestStatus(t *testing.T) { - type TestCase struct { - name string - resp *seqapi.StatusResponse - clientErr error + type mockArgs struct { + resp *seqapi.StatusResponse + err error } - someMoment := time.Now() + tests := []struct { + name string - tests := []TestCase{ + want *seqapi.StatusResponse + wantCode codes.Code + + mockArgs *mockArgs + }{ { name: "ok", - resp: &seqapi.StatusResponse{ + want: &seqapi.StatusResponse{ NumberOfStores: 3, OldestStorageTime: timestamppb.New(someMoment), Stores: []*seqapi.StoreStatus{ @@ -47,37 +51,63 @@ func TestStatus(t *testing.T) { }, }, }, + mockArgs: &mockArgs{ + resp: &seqapi.StatusResponse{ + NumberOfStores: 3, + OldestStorageTime: timestamppb.New(someMoment), + Stores: []*seqapi.StoreStatus{ + { + Host: "host-0", + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment)}, + }, + { + Host: "host-1", + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment.Add(1 * time.Hour))}, + }, + { + Host: "host-2", + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment.Add(2 * time.Hour))}, + }, + }, + }, + }, }, { - name: "err_client", - clientErr: errors.New("client error"), + name: "err_client", + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: status.Error(codes.Internal, "client error"), + }, }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().Status(gomock.Any(), nil). - Return(proto.Clone(tt.resp), tt.clientErr).Times(1) - cfg := config.SeqAPI{} + seqDbMock.EXPECT(). + Status(gomock.Any(), nil). + Return(proto.Clone(tt.mockArgs.resp), tt.mockArgs.err). + Times(1) seqData := test.APITestData{ - Cfg: cfg, Mocks: test.Mocks{ SeqDB: seqDbMock, }, } - s := initTestAPI(seqData) - resp, err := s.Status(context.Background(), nil) - require.Equal(t, tt.clientErr, err) - require.True(t, proto.Equal(tt.resp, resp)) + api := setupAPI(seqData) + + got, err := api.Status(context.Background(), nil) + + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + require.True(t, proto.Equal(tt.want, got)) }) } } diff --git a/internal/api/seqapi/v1/grpc/delete_async_search.go b/internal/api/seqapi/v1/grpc/delete_async_search.go index 98b3928..4c573ea 100644 --- a/internal/api/seqapi/v1/grpc/delete_async_search.go +++ b/internal/api/seqapi/v1/grpc/delete_async_search.go @@ -14,10 +14,7 @@ import ( "github.com/ozontech/seq-ui/tracing" ) -func (a *API) DeleteAsyncSearch( - ctx context.Context, - req *seqapi.DeleteAsyncSearchRequest, -) (*seqapi.DeleteAsyncSearchResponse, error) { +func (a *API) DeleteAsyncSearch(ctx context.Context, req *seqapi.DeleteAsyncSearchRequest) (*seqapi.DeleteAsyncSearchResponse, error) { if a.asyncSearches == nil { return nil, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()) } @@ -36,12 +33,7 @@ func (a *API) DeleteAsyncSearch( }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - - resp, err := a.asyncSearches.DeleteAsyncSearch(ctx, profileID, req) + resp, err := a.asyncSearches.DeleteAsyncSearch(ctx, req) if err != nil { return nil, grpcutil.ProcessError(err) } diff --git a/internal/api/seqapi/v1/grpc/delete_async_search_test.go b/internal/api/seqapi/v1/grpc/delete_async_search_test.go index f785ad4..e1bac7c 100644 --- a/internal/api/seqapi/v1/grpc/delete_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/delete_async_search_test.go @@ -8,104 +8,64 @@ import ( "go.uber.org/mock/gomock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) -func TestServeDeleteAsyncSearch(t *testing.T) { - const ( - mockSearchID1 = "69e4a4a6-0922-43bd-952d-060a86c2b622" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - mockProfileID1 = 1 - mockProfileID2 = 2 - ) - +func TestDeleteAsyncSearch(t *testing.T) { type mockArgs struct { - userName string - - profilesReq *types.GetOrCreateUserProfileRequest - profilesResp *types.UserProfile - profilesErr error - - repoGetAsyncSearchResp *types.AsyncSearchInfo - repoGetAsyncSearchErr error - - repoDeleteAsyncSearchErr error + req *seqapi.DeleteAsyncSearchRequest + resp *seqapi.DeleteAsyncSearchResponse + err error } tests := []struct { name string - req *seqapi.DeleteAsyncSearchRequest - resp *seqapi.DeleteAsyncSearchResponse - err error - - shouldDelete bool + req *seqapi.DeleteAsyncSearchRequest + want *seqapi.DeleteAsyncSearchResponse + wantCode codes.Code mockArgs *mockArgs }{ { name: "ok", req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID1, + SearchId: mockSearchID, }, - resp: &seqapi.DeleteAsyncSearchResponse{}, + want: &seqapi.DeleteAsyncSearchResponse{}, mockArgs: &mockArgs{ - userName: mockUserName1, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoGetAsyncSearchResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, + req: &seqapi.DeleteAsyncSearchRequest{ + SearchId: mockSearchID, }, + resp: &seqapi.DeleteAsyncSearchResponse{}, }, - shouldDelete: true, }, { - name: "err_permission_denied", + name: "invalid_id", req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID1, - }, - mockArgs: &mockArgs{ - userName: mockUserName1, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoGetAsyncSearchResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID2, - OwnerName: mockUserName2, - }, + SearchId: "some_invalid_id", }, - err: status.Error(codes.PermissionDenied, "permission denied: delete async search"), + wantCode: codes.InvalidArgument, }, { - name: "invalid id", + name: "err_svc", req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: "some_invalid_id", + SearchId: mockSearchID, }, + wantCode: codes.Internal, mockArgs: &mockArgs{ - userName: mockUserName1, + req: &seqapi.DeleteAsyncSearchRequest{ + SearchId: mockSearchID, + }, + err: errSomethingWrong, }, - err: status.Error(codes.InvalidArgument, "invalid search_id"), }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -115,54 +75,30 @@ func TestServeDeleteAsyncSearch(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) - if tt.err == nil { - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().DeleteAsyncSearch(gomock.Any(), tt.req). - Return(tt.resp, nil).Times(1) - seqData.Mocks.SeqDB = seqDbMock - } - - if tt.mockArgs.profilesResp != nil { - profilesRepoMock := mock_repo.NewMockUserProfiles(ctrl) - profilesRepoMock.EXPECT().GetOrCreate(gomock.Any(), *tt.mockArgs.profilesReq). - Return(*tt.mockArgs.profilesResp, tt.mockArgs.profilesErr).Times(1) - seqData.Mocks.ProfilesRepo = profilesRepoMock - } - - if tt.mockArgs.repoGetAsyncSearchResp != nil { - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchById(gomock.Any(), tt.req.SearchId). - Return(*tt.mockArgs.repoGetAsyncSearchResp, tt.mockArgs.repoGetAsyncSearchErr).Times(1) - - if tt.shouldDelete { - asyncSearchesRepoMock.EXPECT().DeleteAsyncSearch(gomock.Any(), tt.req.SearchId). - Return(tt.mockArgs.repoDeleteAsyncSearchErr).Times(1) - } - - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock - } - } + svcMock := mock_asyncsearches.NewMockService(ctrl) + svcMock.EXPECT(). + DeleteAsyncSearch(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) - api := initTestAPIWithAsyncSearches(seqData) + seqData.Mocks.AsyncSearchesSvc = svcMock + } - ctx := context.Background() - ctx = context.WithValue(ctx, types.UserKey{}, tt.mockArgs.userName) + api := setupAPIWithAsyncSearches(seqData) + got, err := api.DeleteAsyncSearch(context.Background(), tt.req) - resp, err := api.DeleteAsyncSearch(ctx, tt.req) - if tt.err == nil { - require.NoError(t, err) - require.True(t, proto.Equal(tt.resp, resp)) - } else { - require.Error(t, err) - require.Equal(t, tt.err, err) + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return } + require.Equal(t, tt.want, got) }) } } func TestServeDeleteAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) + api := setupAPI(seqData) _, err := api.DeleteAsyncSearch(context.Background(), &seqapi.DeleteAsyncSearchRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/events_test.go b/internal/api/seqapi/v1/grpc/events_test.go index 29b116e..34c99f4 100644 --- a/internal/api/seqapi/v1/grpc/events_test.go +++ b/internal/api/seqapi/v1/grpc/events_test.go @@ -21,18 +21,12 @@ import ( ) func TestGetEvent(t *testing.T) { - eventTime := time.Date(2024, time.December, 31, 10, 20, 30, 400000, time.UTC) - id1 := "test1" - id2 := "test2" - id3 := "test3" - id4 := "test4" - event1 := test.MakeEvent(id1, 1, eventTime) + event1 := test.MakeEvent(id1, 1, someMoment) event1json, _ := proto.Marshal(event1) - event2 := test.MakeEvent(id2, 2, eventTime) + event2 := test.MakeEvent(id2, 2, someMoment) event2json, _ := proto.Marshal(event2) event3 := &seqapi.Event{} event3json, _ := proto.Marshal(event3) - err := errors.New("test error") cacheTTL := time.Minute tests := []struct { @@ -55,7 +49,7 @@ func TestGetEvent(t *testing.T) { cacheArgs: test.CacheMockArgs{ Key: id1, Value: string(event1json), - Err: err, + Err: errSomethingWrong, }, }, { @@ -82,7 +76,7 @@ func TestGetEvent(t *testing.T) { cacheArgs: test.CacheMockArgs{ Key: id3, Value: string(event3json), - Err: err, + Err: errSomethingWrong, }, }, { @@ -92,13 +86,13 @@ func TestGetEvent(t *testing.T) { }, cacheArgs: test.CacheMockArgs{ Key: id4, - Err: err, + Err: errSomethingWrong, }, clientErr: errors.New("client error"), }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -112,23 +106,29 @@ func TestGetEvent(t *testing.T) { ctrl := gomock.NewController(t) cacheMock := mock_cache.NewMockCache(ctrl) - cacheMock.EXPECT().Get(gomock.Any(), tt.cacheArgs.Key). - Return(tt.cacheArgs.Value, tt.cacheArgs.Err).Times(1) + cacheMock.EXPECT(). + Get(gomock.Any(), tt.cacheArgs.Key). + Return(tt.cacheArgs.Value, tt.cacheArgs.Err). + Times(1) seqData.Mocks.Cache = cacheMock if tt.cacheArgs.Err != nil { seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetEvent(gomock.Any(), proto.Clone(tt.req)). - Return(proto.Clone(tt.resp), tt.clientErr).Times(1) + seqDbMock.EXPECT(). + GetEvent(gomock.Any(), proto.Clone(tt.req)). + Return(proto.Clone(tt.resp), tt.clientErr). + Times(1) seqData.Mocks.SeqDB = seqDbMock if tt.clientErr == nil { - cacheMock.EXPECT().SetWithTTL(gomock.Any(), tt.cacheArgs.Key, tt.cacheArgs.Value, cacheTTL). - Return(nil).Times(1) + cacheMock.EXPECT(). + SetWithTTL(gomock.Any(), tt.cacheArgs.Key, tt.cacheArgs.Value, cacheTTL). + Return(nil). + Times(1) } } - s := initTestAPI(seqData) + s := setupAPI(seqData) md := metadata.New(map[string]string{"env": "test"}) ctx := metadata.NewIncomingContext(context.Background(), md) @@ -151,17 +151,11 @@ func TestGetEventWithMasking(t *testing.T) { resp *seqapi.GetEventResponse } - eventTime := time.Date(2024, time.December, 31, 10, 20, 30, 400000, time.UTC) - - cacheErr := errors.New("test error") - cacheTTL := time.Minute - tests := []struct { name string shouldMask bool isCached bool - wantErr error maskingCfg *config.Masking }{ @@ -334,7 +328,7 @@ func TestGetEventWithMasking(t *testing.T) { Data: map[string]string{ eventField: eventVal, }, - Time: timestamppb.New(eventTime), + Time: timestamppb.New(someMoment), } if shouldMask { event.Data[eventField] = "***" @@ -351,13 +345,11 @@ func TestGetEventWithMasking(t *testing.T) { } eventsData := make([]eventData, 0, len(tests)) - for i := 0; i < len(tests); i++ { + for i := range len(tests) { eventsData = append(eventsData, formEventData(i, tests[i].shouldMask)) } for i, tt := range tests { - i := i - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -372,18 +364,20 @@ func TestGetEventWithMasking(t *testing.T) { }, }, } - ctrl := gomock.NewController(t) + ctrl := gomock.NewController(t) cacheMock := mock_cache.NewMockCache(ctrl) cacheArgs := test.CacheMockArgs{ Key: curEID, Value: string(curEData.eventJson), } if !tt.isCached { - cacheArgs.Err = cacheErr + cacheArgs.Err = errCache } - cacheMock.EXPECT().Get(gomock.Any(), cacheArgs.Key). - Return(cacheArgs.Value, cacheArgs.Err).Times(1) + cacheMock.EXPECT(). + Get(gomock.Any(), cacheArgs.Key). + Return(cacheArgs.Value, cacheArgs.Err). + Times(1) seqData.Mocks.Cache = cacheMock if !tt.isCached { @@ -392,25 +386,23 @@ func TestGetEventWithMasking(t *testing.T) { resp: &seqapi.GetEventResponse{Event: curEData.event}, } seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetEvent(gomock.Any(), seqDBArgs.req). - Return(seqDBArgs.resp, nil).Times(1) + seqDbMock.EXPECT(). + GetEvent(gomock.Any(), seqDBArgs.req). + Return(seqDBArgs.resp, nil). + Times(1) seqData.Mocks.SeqDB = seqDbMock - cacheMock.EXPECT().SetWithTTL(gomock.Any(), cacheArgs.Key, cacheArgs.Value, cacheTTL). - Return(nil).Times(1) + cacheMock.EXPECT(). + SetWithTTL(gomock.Any(), cacheArgs.Key, cacheArgs.Value, cacheTTL). + Return(nil). + Times(1) } - s := initTestAPI(seqData) - + api := setupAPI(seqData) req := &seqapi.GetEventRequest{Id: curEID} - resp, err := s.GetEvent(context.Background(), req) - - require.Equal(t, tt.wantErr, err) - if tt.wantErr != nil { - return - } - + resp, err := api.GetEvent(context.Background(), req) + require.NoError(t, err) require.True(t, proto.Equal(curEData.wantResp, resp)) }) } diff --git a/internal/api/seqapi/v1/grpc/fetch_async_search_result.go b/internal/api/seqapi/v1/grpc/fetch_async_search_result.go index 1d3d9fa..3ba0fd4 100644 --- a/internal/api/seqapi/v1/grpc/fetch_async_search_result.go +++ b/internal/api/seqapi/v1/grpc/fetch_async_search_result.go @@ -14,10 +14,7 @@ import ( "github.com/ozontech/seq-ui/tracing" ) -func (a *API) FetchAsyncSearchResult( - ctx context.Context, - req *seqapi.FetchAsyncSearchResultRequest, -) (*seqapi.FetchAsyncSearchResultResponse, error) { +func (a *API) FetchAsyncSearchResult(ctx context.Context, req *seqapi.FetchAsyncSearchResultRequest) (*seqapi.FetchAsyncSearchResultResponse, error) { if a.asyncSearches == nil { return nil, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()) } diff --git a/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go b/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go index 48fdb67..5629fd2 100644 --- a/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go +++ b/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go @@ -9,33 +9,29 @@ import ( "go.uber.org/mock/gomock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeFetchAsyncSearchResult(t *testing.T) { - var ( - mockSearchID = "c9a34cf8-4c66-484e-9cc2-42979d848656" - mockTime = time.Date(2025, 8, 6, 17, 52, 12, 123, time.UTC) - meta = `{"some":"meta"}` - ) + type mockArgs struct { + req *seqapi.FetchAsyncSearchResultRequest + err error + } tests := []struct { name string - req *seqapi.FetchAsyncSearchResultRequest - resp *seqapi.FetchAsyncSearchResultResponse - - repoResp types.AsyncSearchInfo + req *seqapi.FetchAsyncSearchResultRequest + want *seqapi.FetchAsyncSearchResultResponse + wantCode codes.Code - err error + mockArgs *mockArgs }{ { name: "ok", @@ -45,13 +41,13 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Offset: 10, Order: seqapi.Order_ORDER_DESC, }, - resp: &seqapi.FetchAsyncSearchResultResponse{ + want: &seqapi.FetchAsyncSearchResultResponse{ Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -75,7 +71,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(mockTime.Add(-1 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -84,7 +80,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(mockTime.Add(-2 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -108,14 +104,14 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Value: pointerTo(2), NotExists: 0, Quantiles: []float64{2, 1}, - Ts: timestamppb.New(mockTime), + Ts: timestamppb.New(someMoment), }, { Key: "2", Value: pointerTo(8), NotExists: 1, Quantiles: []float64{7, 4}, - Ts: timestamppb.New(mockTime.Add(-1 * time.Minute)), + Ts: timestamppb.New(someMoment.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -126,15 +122,19 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Meta: meta, }, - repoResp: types.AsyncSearchInfo{ - SearchID: mockSearchID, - Meta: meta, + mockArgs: &mockArgs{ + req: &seqapi.FetchAsyncSearchResultRequest{ + SearchId: mockSearchID, + Limit: 2, + Offset: 10, + Order: seqapi.Order_ORDER_DESC, + }, }, }, { @@ -145,13 +145,13 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Offset: 10, Order: seqapi.Order_ORDER_DESC, }, - resp: &seqapi.FetchAsyncSearchResultResponse{ + want: &seqapi.FetchAsyncSearchResultResponse{ Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, @@ -164,7 +164,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(mockTime.Add(-1 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), }, }, Total: 1, @@ -172,8 +172,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Meta: meta, @@ -182,58 +182,75 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "partial response", }, }, - repoResp: types.AsyncSearchInfo{ - SearchID: mockSearchID, - Meta: meta, + mockArgs: &mockArgs{ + req: &seqapi.FetchAsyncSearchResultRequest{ + SearchId: mockSearchID, + Limit: 2, + Offset: 10, + Order: seqapi.Order_ORDER_DESC, + }, }, }, { - name: "invalid id", + name: "invalid_id", req: &seqapi.FetchAsyncSearchResultRequest{ SearchId: "some_invalid_id", }, - err: status.Error(codes.InvalidArgument, "invalid search_id"), + wantCode: codes.InvalidArgument, + }, + { + name: "err_svc", + req: &seqapi.FetchAsyncSearchResultRequest{ + SearchId: mockSearchID, + Limit: 2, + Offset: 10, + Order: seqapi.Order_ORDER_DESC, + }, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + req: &seqapi.FetchAsyncSearchResultRequest{ + SearchId: mockSearchID, + Limit: 2, + Offset: 10, + Order: seqapi.Order_ORDER_DESC, + }, + err: errSomethingWrong, + }, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() seqData := test.APITestData{} - ctrl := gomock.NewController(t) + if tt.mockArgs != nil { + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) - if tt.err == nil { - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchById(gomock.Any(), mockSearchID). - Return(tt.repoResp, nil).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock - - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().FetchAsyncSearchResult(gomock.Any(), tt.req). - Return(tt.resp, nil).Times(1) - seqData.Mocks.SeqDB = seqDbMock + svcMock.EXPECT(). + FetchAsyncSearchResult(gomock.Any(), tt.mockArgs.req). + Return(tt.want, tt.mockArgs.err). + Times(1) + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - - ctx := context.Background() + api := setupAPIWithAsyncSearches(seqData) + got, err := api.FetchAsyncSearchResult(context.Background(), tt.req) - resp, err := api.FetchAsyncSearchResult(ctx, tt.req) - if tt.err == nil { - require.NoError(t, err) - require.True(t, proto.Equal(tt.resp, resp)) - } else { - require.Error(t, err) - require.Equal(t, tt.err, err) + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return } + require.Equal(t, tt.want, got) }) } } func TestServeFetchAsyncSearchResult_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) + api := setupAPI(seqData) _, err := api.FetchAsyncSearchResult(context.Background(), &seqapi.FetchAsyncSearchResultRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/fields_test.go b/internal/api/seqapi/v1/grpc/fields_test.go index 3bdf539..ac9afa8 100644 --- a/internal/api/seqapi/v1/grpc/fields_test.go +++ b/internal/api/seqapi/v1/grpc/fields_test.go @@ -103,16 +103,18 @@ func TestGetFields(t *testing.T) { clientErr: errors.New("client error"), }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetFields(gomock.Any(), nil). - Return(proto.Clone(tt.seqDBResp), tt.clientErr).Times(1) + + seqDbMock.EXPECT(). + GetFields(gomock.Any(), nil). + Return(proto.Clone(tt.seqDBResp), tt.clientErr). + Times(1) seqData := test.APITestData{ Mocks: test.Mocks{ @@ -123,11 +125,8 @@ func TestGetFields(t *testing.T) { }, } - s := initTestAPI(seqData) - - ctx := context.Background() - - resp, err := s.GetFields(ctx, nil) + api := setupAPI(seqData) + resp, err := api.GetFields(context.Background(), nil) require.Equal(t, tt.clientErr, err) require.True(t, proto.Equal(tt.wantResp, resp)) @@ -163,12 +162,12 @@ func TestGetFieldsCached(t *testing.T) { seqDbMock := mock_seqdb.NewMockClient(ctrl) for _, r := range responses { - seqDbMock.EXPECT().GetFields(gomock.Any(), nil). - Return(proto.Clone(r), nil).Times(1) + seqDbMock.EXPECT(). + GetFields(gomock.Any(), nil). + Return(proto.Clone(r), nil). + Times(1) } - const ttl = 20 * time.Millisecond - seqData := test.APITestData{ Cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ @@ -179,16 +178,17 @@ func TestGetFieldsCached(t *testing.T) { SeqDB: seqDbMock, }, } - s := initTestAPI(seqData) + + api := setupAPI(seqData) for _, r := range responses { - resp, err := s.GetFields(context.Background(), nil) + resp, err := api.GetFields(context.Background(), nil) require.NoError(t, err) require.True(t, proto.Equal(r, resp)) time.Sleep(ttl / 2) - resp, err = s.GetFields(context.Background(), nil) + resp, err = api.GetFields(context.Background(), nil) require.NoError(t, err) require.True(t, proto.Equal(r, resp)) @@ -212,8 +212,8 @@ func TestGetPinnedFields(t *testing.T) { name: "empty", }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -224,9 +224,10 @@ func TestGetPinnedFields(t *testing.T) { }, }, } - s := initTestAPI(seqData) - resp, err := s.GetPinnedFields(context.Background(), nil) + api := setupAPI(seqData) + + resp, err := api.GetPinnedFields(context.Background(), nil) require.NoError(t, err) require.Equal(t, len(tt.fields), len(resp.Fields)) diff --git a/internal/api/seqapi/v1/grpc/get_async_searches_list.go b/internal/api/seqapi/v1/grpc/get_async_searches_list.go index f60cb9e..b639207 100644 --- a/internal/api/seqapi/v1/grpc/get_async_searches_list.go +++ b/internal/api/seqapi/v1/grpc/get_async_searches_list.go @@ -13,10 +13,7 @@ import ( "github.com/ozontech/seq-ui/tracing" ) -func (a *API) GetAsyncSearchesList( - ctx context.Context, - req *seqapi.GetAsyncSearchesListRequest, -) (*seqapi.GetAsyncSearchesListResponse, error) { +func (a *API) GetAsyncSearchesList(ctx context.Context, req *seqapi.GetAsyncSearchesListRequest) (*seqapi.GetAsyncSearchesListResponse, error) { if a.asyncSearches == nil { return nil, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()) } diff --git a/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go b/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go index 9b6c994..ffd077d 100644 --- a/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go +++ b/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go @@ -9,65 +9,48 @@ import ( "go.uber.org/mock/gomock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeGetAsyncSearchesList(t *testing.T) { - var ( - mockSearchID1 = "c9a34cf8-4c66-484e-9cc2-42979d848656" - mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - mockProfileID1 int64 = 1 - mockProfileID2 int64 = 1 - errorMsg = "some error" - - mockTime = time.Date(2025, 8, 6, 17, 52, 12, 123, time.UTC) - ) - type mockArgs struct { - searchIDs []string - - repoReq types.GetAsyncSearchesListRequest - repoResp []types.AsyncSearchInfo - repoErr error + req *seqapi.GetAsyncSearchesListRequest + err error } tests := []struct { name string - req *seqapi.GetAsyncSearchesListRequest - resp *seqapi.GetAsyncSearchesListResponse - err error + req *seqapi.GetAsyncSearchesListRequest + want *seqapi.GetAsyncSearchesListResponse + wantCode codes.Code mockArgs *mockArgs }{ { name: "ok_no_filters", req: &seqapi.GetAsyncSearchesListRequest{}, - resp: &seqapi.GetAsyncSearchesListResponse{ + want: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -79,8 +62,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(mockTime.Add(-1 * time.Hour)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-1 * time.Hour)), + To: timestamppb.New(someMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -93,9 +76,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(mockTime.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(300 * time.Second)), - CanceledAt: timestamppb.New(mockTime), + StartedAt: timestamppb.New(someMoment.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(300 * time.Second)), + CanceledAt: timestamppb.New(someMoment), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -103,20 +86,7 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, }, mockArgs: &mockArgs{ - repoReq: types.GetAsyncSearchesListRequest{}, - repoResp: []types.AsyncSearchInfo{ - { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, - }, - { - SearchID: mockSearchID2, - OwnerID: mockProfileID2, - OwnerName: mockUserName2, - }, - }, - searchIDs: []string{mockSearchID1, mockSearchID2}, + req: &seqapi.GetAsyncSearchesListRequest{}, }, }, { @@ -127,21 +97,21 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Limit: 10, Offset: 20, }, - resp: &seqapi.GetAsyncSearchesListResponse{ + want: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -149,37 +119,32 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, }, mockArgs: &mockArgs{ - repoReq: types.GetAsyncSearchesListRequest{ - Owner: &mockUserName1, + req: &seqapi.GetAsyncSearchesListRequest{ + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE.Enum(), + OwnerName: &mockUserName1, + Limit: 10, + Offset: 20, }, - repoResp: []types.AsyncSearchInfo{ - { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, - }, - }, - searchIDs: []string{mockSearchID1}, }, }, { name: "partial_response", req: &seqapi.GetAsyncSearchesListRequest{}, - resp: &seqapi.GetAsyncSearchesListResponse{ + want: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -191,15 +156,7 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, }, mockArgs: &mockArgs{ - repoReq: types.GetAsyncSearchesListRequest{}, - repoResp: []types.AsyncSearchInfo{ - { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, - }, - }, - searchIDs: []string{mockSearchID1}, + req: &seqapi.GetAsyncSearchesListRequest{}, }, }, { @@ -208,7 +165,7 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Limit: -10, Offset: 10, }, - err: status.Error(codes.InvalidArgument, "invalid request field: 'limit' must be non-negative"), + wantCode: codes.InvalidArgument, }, { name: "err_offset", @@ -216,9 +173,10 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Limit: 10, Offset: -10, }, - err: status.Error(codes.InvalidArgument, "invalid request field: 'offset' must be non-negative"), + wantCode: codes.InvalidArgument, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -227,37 +185,31 @@ func TestServeGetAsyncSearchesList(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchesList(gomock.Any(), tt.mockArgs.repoReq). - Return(tt.mockArgs.repoResp, tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock + svcMock.EXPECT(). + GetAsyncSearchesList(gomock.Any(), tt.mockArgs.req). + Return(tt.want, tt.mockArgs.err). + Times(1) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetAsyncSearchesList(gomock.Any(), tt.req, tt.mockArgs.searchIDs). - Return(tt.resp, nil).Times(1) - seqData.Mocks.SeqDB = seqDbMock + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - - ctx := context.Background() + api := setupAPIWithAsyncSearches(seqData) + got, err := api.GetAsyncSearchesList(context.Background(), tt.req) - resp, err := api.GetAsyncSearchesList(ctx, tt.req) - if tt.err == nil { - require.NoError(t, err) - require.True(t, proto.Equal(tt.resp, resp)) - } else { - require.Error(t, err) - require.Equal(t, tt.err, err) + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return } + require.Equal(t, tt.want, got) }) } } func TestServeGetAsyncSearchesList_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) + api := setupAPI(seqData) _, err := api.GetAsyncSearchesList(context.Background(), &seqapi.GetAsyncSearchesListRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/get_envs_test.go b/internal/api/seqapi/v1/grpc/get_envs_test.go index 7f8140e..5f5a1a4 100644 --- a/internal/api/seqapi/v1/grpc/get_envs_test.go +++ b/internal/api/seqapi/v1/grpc/get_envs_test.go @@ -141,7 +141,6 @@ func TestGetEnvs(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() api := API{ diff --git a/internal/api/seqapi/v1/grpc/histogram_test.go b/internal/api/seqapi/v1/grpc/histogram_test.go index aa75fda..54ed440 100644 --- a/internal/api/seqapi/v1/grpc/histogram_test.go +++ b/internal/api/seqapi/v1/grpc/histogram_test.go @@ -2,9 +2,7 @@ package grpc import ( "context" - "errors" "testing" - "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -17,16 +15,11 @@ import ( ) func TestGetHistogram(t *testing.T) { - query := "message:error" - from := time.Now() - to := from.Add(time.Second) - interval := "5s" - tests := []struct { name string req *seqapi.GetHistogramRequest - resp *seqapi.GetHistogramResponse + want *seqapi.GetHistogramResponse clientErr error }{ @@ -38,7 +31,7 @@ func TestGetHistogram(t *testing.T) { To: timestamppb.New(to), Interval: interval, }, - resp: &seqapi.GetHistogramResponse{ + want: &seqapi.GetHistogramResponse{ Histogram: test.MakeHistogram(5), Error: &seqapi.Error{ Code: seqapi.ErrorCode_ERROR_CODE_NO, @@ -50,11 +43,11 @@ func TestGetHistogram(t *testing.T) { req: &seqapi.GetHistogramRequest{ Interval: interval, }, - clientErr: errors.New("client error"), + clientErr: errSomethingWrong, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -63,16 +56,17 @@ func TestGetHistogram(t *testing.T) { ctrl := gomock.NewController(t) seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetHistogram(gomock.Any(), proto.Clone(tt.req)). - Return(proto.Clone(tt.resp), tt.clientErr).Times(1) - + seqDbMock.EXPECT(). + GetHistogram(gomock.Any(), proto.Clone(tt.req)). + Return(proto.Clone(tt.want), tt.clientErr). + Times(1) seqData.Mocks.SeqDB = seqDbMock - s := initTestAPI(seqData) - resp, err := s.GetHistogram(context.Background(), tt.req) + api := setupAPI(seqData) + resp, err := api.GetHistogram(context.Background(), tt.req) require.Equal(t, tt.clientErr, err) - require.True(t, proto.Equal(tt.resp, resp)) + require.True(t, proto.Equal(tt.want, resp)) }) } } diff --git a/internal/api/seqapi/v1/grpc/limits_test.go b/internal/api/seqapi/v1/grpc/limits_test.go index c361d79..0d9eb76 100644 --- a/internal/api/seqapi/v1/grpc/limits_test.go +++ b/internal/api/seqapi/v1/grpc/limits_test.go @@ -43,15 +43,15 @@ func TestGetLimits(t *testing.T) { want: &seqapi.GetLimitsResponse{}, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() seqData := test.APITestData{ Cfg: tt.cfg, } - s := initTestAPI(seqData) + s := setupAPI(seqData) resp, err := s.GetLimits(context.Background(), nil) require.NoError(t, err) diff --git a/internal/api/seqapi/v1/grpc/logs_lifespan_test.go b/internal/api/seqapi/v1/grpc/logs_lifespan_test.go index 872f927..28492ef 100644 --- a/internal/api/seqapi/v1/grpc/logs_lifespan_test.go +++ b/internal/api/seqapi/v1/grpc/logs_lifespan_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "strconv" "testing" "time" @@ -22,21 +21,11 @@ import ( ) func TestGetLogsLifespan(t *testing.T) { - const ( - cacheKey = "logs_lifespan" - cacheTTL = 1 * time.Minute - - result = 10 * time.Hour - resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) - ) - unparsable := func(s string) bool { _, err := strconv.Atoi(s) return err != nil } - oldestStorageTime := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC) - tests := []struct { name string @@ -66,7 +55,7 @@ func TestGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(oldestStorageTime), + OldestStorageTime: timestamppb.New(someMoment), }, resp: &seqapi.GetLogsLifespanResponse{ Lifespan: durationpb.New(result), @@ -81,7 +70,7 @@ func TestGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(oldestStorageTime), + OldestStorageTime: timestamppb.New(someMoment), }, resp: &seqapi.GetLogsLifespanResponse{ Lifespan: durationpb.New(result), @@ -92,7 +81,7 @@ func TestGetLogsLifespan(t *testing.T) { getOp: test.CacheMockArgs{ Err: cache.ErrNotFound, }, - clientErr: errors.New("network error"), + clientErr: errSomethingWrong, }, { name: "err_nil_oldest_storage_time", @@ -104,8 +93,8 @@ func TestGetLogsLifespan(t *testing.T) { }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -117,28 +106,35 @@ func TestGetLogsLifespan(t *testing.T) { }, }, } - ctrl := gomock.NewController(t) + ctrl := gomock.NewController(t) cacheMock := mock_cache.NewMockCache(ctrl) - cacheMock.EXPECT().Get(gomock.Any(), cacheKey). - Return(tt.getOp.Value, tt.getOp.Err).Times(1) + + cacheMock.EXPECT(). + Get(gomock.Any(), cacheKey). + Return(tt.getOp.Value, tt.getOp.Err). + Times(1) seqData.Mocks.Cache = cacheMock if tt.getOp.Err != nil || unparsable(tt.getOp.Value) { seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().Status(gomock.Any(), gomock.Any()). - Return(proto.Clone(tt.clientResp), tt.clientErr).Times(1) + seqDbMock.EXPECT(). + Status(gomock.Any(), gomock.Any()). + Return(proto.Clone(tt.clientResp), tt.clientErr). + Times(1) seqData.Mocks.SeqDB = seqDbMock if tt.clientErr == nil && tt.clientResp.OldestStorageTime != nil { - cacheMock.EXPECT().SetWithTTL(gomock.Any(), cacheKey, tt.setOp.Value, cacheTTL). - Return(tt.setOp.Err).Times(1) + cacheMock.EXPECT(). + SetWithTTL(gomock.Any(), cacheKey, tt.setOp.Value, cacheTTL). + Return(tt.setOp.Err). + Times(1) } } - s := initTestAPI(seqData) + s := setupAPI(seqData) s.nowFn = func() time.Time { - return oldestStorageTime.Add(result) + return someMoment.Add(result) } resp, err := s.GetLogsLifespan(context.Background(), nil) diff --git a/internal/api/seqapi/v1/grpc/search_test.go b/internal/api/seqapi/v1/grpc/search_test.go index d83d22a..4a26218 100644 --- a/internal/api/seqapi/v1/grpc/search_test.go +++ b/internal/api/seqapi/v1/grpc/search_test.go @@ -2,9 +2,7 @@ package grpc import ( "context" - "errors" "testing" - "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -19,13 +17,6 @@ import ( ) func TestSearch(t *testing.T) { - query := "message:error" - from := time.Now() - to := from.Add(time.Second) - var limit int32 = 3 - - eventTime := time.Date(2024, time.December, 31, 10, 20, 30, 400000, time.UTC) - tests := []struct { name string @@ -57,7 +48,7 @@ func TestSearch(t *testing.T) { Order: seqapi.Order_ORDER_ASC, }, resp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), eventTime), + Events: test.MakeEvents(int(limit), someMoment), Total: int64(limit), Histogram: test.MakeHistogram(2), Aggregations: test.MakeAggregations(2, 2, nil), @@ -137,11 +128,11 @@ func TestSearch(t *testing.T) { WithTotal: true, }, resp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), eventTime), + Events: test.MakeEvents(int(limit), someMoment), Total: int64(limit) + 1, }, wantResp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), eventTime), + Events: test.MakeEvents(int(limit), someMoment), Total: int64(limit) + 1, Error: &seqapi.Error{ Code: seqapi.ErrorCode_ERROR_CODE_QUERY_TOO_HEAVY, @@ -169,11 +160,11 @@ func TestSearch(t *testing.T) { MaxSearchLimit: 5, }, }), - clientErr: errors.New("client error"), + clientErr: errSomethingWrong, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -185,14 +176,16 @@ func TestSearch(t *testing.T) { ctrl := gomock.NewController(t) seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().Search(gomock.Any(), proto.Clone(tt.req)). - Return(proto.Clone(tt.resp), tt.clientErr).Times(1) + seqDbMock.EXPECT(). + Search(gomock.Any(), proto.Clone(tt.req)). + Return(proto.Clone(tt.resp), tt.clientErr). + Times(1) seqData.Mocks.SeqDB = seqDbMock } - s := initTestAPI(seqData) - resp, err := s.Search(context.Background(), tt.req) + api := setupAPI(seqData) + resp, err := api.Search(context.Background(), tt.req) if tt.apiErr { require.NotNil(t, err) return diff --git a/internal/api/seqapi/v1/grpc/start_async_search.go b/internal/api/seqapi/v1/grpc/start_async_search.go index 4c31659..86641ed 100644 --- a/internal/api/seqapi/v1/grpc/start_async_search.go +++ b/internal/api/seqapi/v1/grpc/start_async_search.go @@ -14,10 +14,7 @@ import ( "github.com/ozontech/seq-ui/tracing" ) -func (a *API) StartAsyncSearch( - ctx context.Context, - req *seqapi.StartAsyncSearchRequest, -) (*seqapi.StartAsyncSearchResponse, error) { +func (a *API) StartAsyncSearch(ctx context.Context, req *seqapi.StartAsyncSearchRequest) (*seqapi.StartAsyncSearchResponse, error) { if a.asyncSearches == nil { return nil, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()) } @@ -67,12 +64,7 @@ func (a *API) StartAsyncSearch( span.SetAttributes(spanAttributes...) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } - - resp, err := a.asyncSearches.StartAsyncSearch(ctx, profileID, req) + resp, err := a.asyncSearches.StartAsyncSearch(ctx, req) if err != nil { return nil, grpcutil.ProcessError(err) } diff --git a/internal/api/seqapi/v1/grpc/start_async_search_test.go b/internal/api/seqapi/v1/grpc/start_async_search_test.go index 14c0dd9..8b031d5 100644 --- a/internal/api/seqapi/v1/grpc/start_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/start_async_search_test.go @@ -9,43 +9,27 @@ import ( "go.uber.org/mock/gomock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeStartAsyncSearch(t *testing.T) { - const ( - mockSearchID = "c9a34cf8-4c66-484e-9cc2-42979d848656" - mockUserName = "some_user" - mockProfileID = 1 - meta = `{"some":"meta"}` - ) - - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(time.Second) - type mockArgs struct { - profilesReq types.GetOrCreateUserProfileRequest - profilesResp types.UserProfile - profilesErr error - - repoReq types.SaveAsyncSearchRequest - repoErr error + resp *seqapi.StartAsyncSearchResponse + err error } tests := []struct { name string - req *seqapi.StartAsyncSearchRequest - resp *seqapi.StartAsyncSearchResponse + req *seqapi.StartAsyncSearchRequest + want *seqapi.StartAsyncSearchResponse + wantCode codes.Code mockArgs *mockArgs }{ @@ -71,25 +55,44 @@ func TestServeStartAsyncSearch(t *testing.T) { }, Meta: meta, }, - resp: &seqapi.StartAsyncSearchResponse{ + want: &seqapi.StartAsyncSearchResponse{ SearchId: mockSearchID, }, mockArgs: &mockArgs{ - profilesReq: types.GetOrCreateUserProfileRequest{ - UserName: mockUserName, + resp: &seqapi.StartAsyncSearchResponse{ + SearchId: mockSearchID, }, - profilesResp: types.UserProfile{ - ID: mockProfileID, - UserName: mockUserName, + }, + }, + { + name: "err_svc", + req: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(to), + WithDocs: true, + Size: 100, + Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ + Interval: "1s", }, - repoReq: types.SaveAsyncSearchRequest{ - SearchID: mockSearchID, - OwnerID: mockProfileID, - Meta: meta, + Aggs: []*seqapi.AggregationQuery{ + { + Field: "v", + GroupBy: "level", + Func: seqapi.AggFunc_AGG_FUNC_AVG, + Quantiles: []float64{0.95}, + }, }, + Meta: meta, + }, + wantCode: codes.Internal, + mockArgs: &mockArgs{ + err: errSomethingWrong, }, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -98,39 +101,31 @@ func TestServeStartAsyncSearch(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().StartAsyncSearch(gomock.Any(), tt.req). - Return(tt.resp, nil).Times(1) - seqData.Mocks.SeqDB = seqDbMock + svcMock.EXPECT(). + StartAsyncSearch(gomock.Any(), tt.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) - profilesRepoMock := mock_repo.NewMockUserProfiles(ctrl) - profilesRepoMock.EXPECT().GetOrCreate(gomock.Any(), tt.mockArgs.profilesReq). - Return(tt.mockArgs.profilesResp, tt.mockArgs.profilesErr).Times(1) - seqData.Mocks.ProfilesRepo = profilesRepoMock - - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().SaveAsyncSearch(gomock.Any(), gomock.Any()). - Return(tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - - ctx := context.Background() - ctx = context.WithValue(ctx, types.UserKey{}, mockUserName) + api := setupAPIWithAsyncSearches(seqData) + got, err := api.StartAsyncSearch(context.Background(), tt.req) - resp, err := api.StartAsyncSearch(ctx, tt.req) - require.NoError(t, err) - - require.True(t, proto.Equal(tt.resp, resp)) + require.Equal(t, tt.wantCode, status.Code(err)) + if tt.wantCode != codes.OK { + return + } + require.Equal(t, tt.want, got) }) } } func TestServeStartAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) + api := setupAPI(seqData) _, err := api.StartAsyncSearch(context.Background(), &seqapi.StartAsyncSearchRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/test_data.go b/internal/api/seqapi/v1/grpc/test_data.go index 4b605ea..fb03c16 100644 --- a/internal/api/seqapi/v1/grpc/test_data.go +++ b/internal/api/seqapi/v1/grpc/test_data.go @@ -1,18 +1,42 @@ package grpc import ( - "context" + "errors" + "time" - "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/config" "github.com/ozontech/seq-ui/internal/pkg/client/seqdb" - "github.com/ozontech/seq-ui/internal/pkg/repository" - "github.com/ozontech/seq-ui/internal/pkg/service" - asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches" ) -func initTestAPI(data test.APITestData) *API { +var ( + errSomethingWrong = errors.New("something happened wrong") + errCache = errors.New("test error") + errorMsg = "some err" + mockSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" + mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" + mockUserName1 = "some_user_1" + mockUserName2 = "some_user_2" + id1 = "test1" + id2 = "test2" + id3 = "test3" + id4 = "test4" + query = "message:error" + cacheKey = "logs_lifespan" + targetBucketRate = "3s" + interval = "2s" + resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) + meta = `{"some":"meta"}` + someMoment = time.Now() + from = time.Now() + to = from.Add(time.Second) + cacheTTL = time.Minute + ttl = 10 * time.Millisecond + result = 10 * time.Hour + limit int32 = 3 +) + +func setupAPI(data test.APITestData) *API { // when test cases don't explicitly provide configuration if data.Cfg.SeqAPIOptions == nil { data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} @@ -24,20 +48,16 @@ func initTestAPI(data test.APITestData) *API { seqDBClients[envConfig.SeqDB] = data.Mocks.SeqDB } - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, nil, nil) + return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, nil) } -func initTestAPIWithAsyncSearches(data test.APITestData) *API { +func setupAPIWithAsyncSearches(data test.APITestData) *API { if data.Cfg.SeqAPIOptions == nil { data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} } seqDBClients := map[string]seqdb.Client{ config.DefaultSeqDBClientID: data.Mocks.SeqDB, } - as := asyncsearches.New(context.Background(), data.Mocks.AsyncSearchesRepo, data.Mocks.SeqDB, data.AsyncCfg) - s := service.New(&repository.Repository{ - UserProfiles: data.Mocks.ProfilesRepo, - }) - p := profiles.New(s) - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, as, p) + + return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, data.Mocks.AsyncSearchesSvc) } diff --git a/internal/api/seqapi/v1/http/aggregation_test.go b/internal/api/seqapi/v1/http/aggregation_test.go index d567c8a..7b53e29 100644 --- a/internal/api/seqapi/v1/http/aggregation_test.go +++ b/internal/api/seqapi/v1/http/aggregation_test.go @@ -1,16 +1,10 @@ package http import ( - "encoding/json" "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" - "time" - "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -22,21 +16,6 @@ import ( ) func TestServeGetAggregation(t *testing.T) { - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(time.Second) - - formatReqBody := func(aggField string, aggQueries aggregationQueries) string { - if len(aggQueries) > 0 { - aggQueriesRaw, err := json.Marshal(aggQueries) - assert.NoError(t, err) - return fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"aggField":%q,"aggregations":%s}`, - query, from.Format(time.RFC3339), to.Format(time.RFC3339), aggField, aggQueriesRaw) - } - return fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"aggField":%q}`, - query, from.Format(time.RFC3339), to.Format(time.RFC3339), aggField) - } - type mockArgs struct { req *seqapi.GetAggregationRequest resp *seqapi.GetAggregationResponse @@ -46,16 +25,21 @@ func TestServeGetAggregation(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req getAggregationRequest + want getAggregationResponse + wantErr bool mockArgs *mockArgs cfg config.SeqAPI }{ { - name: "ok_single_agg", - reqBody: formatReqBody("test_single", nil), + name: "ok_single_agg", + req: getAggregationRequest{ + Query: query, + From: from, + To: to, + AggField: "test_single", + }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: query, @@ -71,8 +55,12 @@ func TestServeGetAggregation(t *testing.T) { }, }, }, - wantRespBody: `{"aggregation":{"buckets":[{"key":"test1","value":1},{"key":"test2","value":2}]},"aggregations":[{"buckets":[{"key":"test1","value":1},{"key":"test2","value":2}]}],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + want: getAggregationResponse{ + Aggregation: aggregationFromProto(test.MakeAggregation(2, nil)), + Aggregations: aggregationsFromProto(test.MakeAggregations(1, 2, nil), true), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 3, @@ -81,11 +69,16 @@ func TestServeGetAggregation(t *testing.T) { }, { name: "ok_multi_agg", - reqBody: formatReqBody("", aggregationQueries{ - {Field: "test_multi1"}, - {Field: "test_multi2"}, - {Field: "test_multi3"}, - }), + req: getAggregationRequest{ + Query: query, + From: from, + To: to, + Aggregations: aggregationQueries{ + {Field: "test_multi1"}, + {Field: "test_multi2"}, + {Field: "test_multi3"}, + }, + }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: query, @@ -105,8 +98,12 @@ func TestServeGetAggregation(t *testing.T) { }, }, }, - wantRespBody: `{"aggregation":{"buckets":[{"key":"test1","value":1},{"key":"test2","value":2},{"key":"test3","value":3}]},"aggregations":[{"buckets":[{"key":"test1","value":1},{"key":"test2","value":2},{"key":"test3","value":3}]},{"buckets":[{"key":"test1","value":1},{"key":"test2","value":2},{"key":"test3","value":3}]}],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + want: getAggregationResponse{ + Aggregation: aggregationFromProto(test.MakeAggregation(3, nil)), + Aggregations: aggregationsFromProto(test.MakeAggregations(2, 3, nil), true), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 3, @@ -116,14 +113,19 @@ func TestServeGetAggregation(t *testing.T) { { name: "ok_agg_quantile", - reqBody: formatReqBody("", aggregationQueries{ - { - Field: "test_multi1", - GroupBy: "service", - Func: afQuantile, - Quantiles: []float64{0.95, 0.99}, - }, - }), + req: getAggregationRequest{ + Query: query, + From: from, + To: to, + Aggregations: aggregationQueries{ + { + Field: "test_multi1", + GroupBy: "service", + Func: afQuantile, + Quantiles: []float64{0.95, 0.99}, + }, + }, + }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: query, @@ -152,8 +154,18 @@ func TestServeGetAggregation(t *testing.T) { }, }, }, - wantRespBody: `{"aggregation":{"buckets":[{"key":"test1","value":1,"not_exists":10,"quantiles":[100,150]},{"key":"test2","value":2,"not_exists":10,"quantiles":[100,150]},{"key":"test3","value":3,"not_exists":10,"quantiles":[100,150]}]},"aggregations":[{"buckets":[{"key":"test1","value":1,"not_exists":10,"quantiles":[100,150]},{"key":"test2","value":2,"not_exists":10,"quantiles":[100,150]},{"key":"test3","value":3,"not_exists":10,"quantiles":[100,150]}]},{"buckets":[{"key":"test1","value":1,"not_exists":10,"quantiles":[100,150]},{"key":"test2","value":2,"not_exists":10,"quantiles":[100,150]},{"key":"test3","value":3,"not_exists":10,"quantiles":[100,150]}]}],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + want: getAggregationResponse{ + Aggregation: aggregationFromProto(test.MakeAggregation(3, &test.MakeAggOpts{ + NotExists: 10, + Quantiles: []float64{100, 150}, + })), + Aggregations: aggregationsFromProto(test.MakeAggregations(2, 3, &test.MakeAggOpts{ + NotExists: 10, + Quantiles: []float64{100, 150}, + }), true), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 3, @@ -161,8 +173,13 @@ func TestServeGetAggregation(t *testing.T) { }, }, { - name: "err_partial_response", - reqBody: formatReqBody("test_err_partial", nil), + name: "err_partial_response", + req: getAggregationRequest{ + Query: query, + From: from, + To: to, + AggField: "test_err_partial", + }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: query, @@ -178,8 +195,12 @@ func TestServeGetAggregation(t *testing.T) { PartialResponse: true, }, }, - wantRespBody: `{"aggregation":{"buckets":[]},"aggregations":[],"error":{"code":"ERROR_CODE_PARTIAL_RESPONSE","message":"partial response"},"partialResponse":true}`, - wantStatus: http.StatusOK, + want: getAggregationResponse{ + Aggregation: aggregationFromProto(nil), + Aggregations: aggregationsFromProto(nil, true), + Error: apiError{Code: aecPartialResponse, Message: "partial response"}, + PartialResponse: true, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 3, @@ -187,14 +208,14 @@ func TestServeGetAggregation(t *testing.T) { }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - }, - { - name: "err_aggs_limit_max", - reqBody: formatReqBody("", aggregationQueries{{}, {}, {}}), - wantStatus: http.StatusBadRequest, + name: "err_aggs_limit_max", + req: getAggregationRequest{ + Query: query, + From: from, + To: to, + Aggregations: aggregationQueries{{}, {}, {}}, + }, + wantErr: true, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 2, @@ -202,8 +223,13 @@ func TestServeGetAggregation(t *testing.T) { }, }, { - name: "err_client", - reqBody: formatReqBody("test_err_client", nil), + name: "err_client", + req: getAggregationRequest{ + Query: query, + From: from, + To: to, + AggField: "test_err_client", + }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: query, @@ -213,7 +239,7 @@ func TestServeGetAggregation(t *testing.T) { }, err: errors.New("client error"), }, - wantStatus: http.StatusInternalServerError, + wantErr: true, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 3, @@ -221,8 +247,8 @@ func TestServeGetAggregation(t *testing.T) { }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -232,21 +258,25 @@ func TestServeGetAggregation(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetAggregation(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) + + seqDbMock.EXPECT(). + GetAggregation(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) seqData.Mocks.SeqDB = seqDbMock } - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/aggregation", strings.NewReader(tt.reqBody)) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetAggregation, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + api := setupAPI(seqData) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAggregationRequest, getAggregationResponse]{ + Method: http.MethodPost, + Target: "/seqapi/v1/aggregation", + Req: tt.req, + Handler: api.serveGetAggregation, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/seqapi/v1/http/aggregation_ts_test.go b/internal/api/seqapi/v1/http/aggregation_ts_test.go index a7b20fa..8f9f99b 100644 --- a/internal/api/seqapi/v1/http/aggregation_ts_test.go +++ b/internal/api/seqapi/v1/http/aggregation_ts_test.go @@ -23,9 +23,6 @@ import ( ) func TestServeGetAggregationTs(t *testing.T) { - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(5 * time.Second) interval := "1s" interval2 := "3000ms" targetBucketRate := "2s" @@ -283,7 +280,7 @@ func TestServeGetAggregationTs(t *testing.T) { cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxAggregationsPerRequest: 3, - MaxBucketsPerAggregationTs: 8, + MaxBucketsPerAggregationTs: 1, }, }, }, @@ -324,7 +321,7 @@ func TestServeGetAggregationTs(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := initTestAPI(seqData) + api := setupAPI(seqData) req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/aggregation_ts", strings.NewReader(tt.reqBody)) httputil.DoTestHTTP(t, httputil.TestDataHTTP{ diff --git a/internal/api/seqapi/v1/http/api.go b/internal/api/seqapi/v1/http/api.go index 1dda605..c762883 100644 --- a/internal/api/seqapi/v1/http/api.go +++ b/internal/api/seqapi/v1/http/api.go @@ -10,7 +10,6 @@ import ( "github.com/gofrs/uuid" "go.uber.org/zap" - "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/app/config" "github.com/ozontech/seq-ui/internal/app/tokenlimiter" "github.com/ozontech/seq-ui/internal/app/types" @@ -39,8 +38,7 @@ type API struct { inmemWithRedisCache cache.Cache redisCache cache.Cache nowFn func() time.Time - asyncSearches *asyncsearches.Service - profiles *profiles.Profiles + asyncSearches asyncsearches.Service envsResponse getEnvsResponse } @@ -49,8 +47,7 @@ func New( seqDBСlients map[string]seqdb.Client, inmemWithRedisCache cache.Cache, redisCache cache.Cache, - asyncSearches *asyncsearches.Service, - p *profiles.Profiles, + asyncSearches asyncsearches.Service, ) *API { var globalfCache *fieldsCache if cfg.FieldsCacheTTL > 0 { @@ -135,7 +132,6 @@ func New( redisCache: redisCache, nowFn: time.Now, asyncSearches: asyncSearches, - profiles: p, envsResponse: parseEnvs(cfg), } } diff --git a/internal/api/seqapi/v1/http/cancel_async_search.go b/internal/api/seqapi/v1/http/cancel_async_search.go index 2c8c4f8..b07776d 100644 --- a/internal/api/seqapi/v1/http/cancel_async_search.go +++ b/internal/api/seqapi/v1/http/cancel_async_search.go @@ -47,15 +47,7 @@ func (a *API) serveCancelAsyncSearch(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - - _, err = a.asyncSearches.CancelAsyncSearch(ctx, profileID, &seqapi.CancelAsyncSearchRequest{ - SearchId: searchID, - }) + _, err := a.asyncSearches.CancelAsyncSearch(ctx, &seqapi.CancelAsyncSearchRequest{SearchId: searchID}) if err != nil { status := http.StatusInternalServerError if errors.Is(err, types.ErrPermissionDenied) { diff --git a/internal/api/seqapi/v1/http/cancel_async_search_test.go b/internal/api/seqapi/v1/http/cancel_async_search_test.go index 053df8b..fb54afd 100644 --- a/internal/api/seqapi/v1/http/cancel_async_search_test.go +++ b/internal/api/seqapi/v1/http/cancel_async_search_test.go @@ -1,115 +1,63 @@ package http import ( - "context" "fmt" "net/http" - "net/http/httptest" "testing" - "github.com/go-chi/chi/v5" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" - "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeCancelAsyncSearch(t *testing.T) { - const ( - mockSearchID1 = "69e4a4a6-0922-43bd-952d-060a86c2b622" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - mockProfileID1 = 1 - mockProfileID2 = 2 - ) - type mockArgs struct { - userName string - - proxyReq *seqapi.CancelAsyncSearchRequest - proxyResp *seqapi.CancelAsyncSearchResponse - proxyErr error - - profilesReq *types.GetOrCreateUserProfileRequest - profilesResp *types.UserProfile - profilesErr error - - repoResp *types.AsyncSearchInfo - repoErr error + req *seqapi.CancelAsyncSearchRequest + resp *seqapi.CancelAsyncSearchResponse + err error } tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + searchID string + wantErr bool + noResp bool mockArgs *mockArgs }{ { - name: "ok", + name: "ok", + searchID: mockSearchID, + noResp: true, mockArgs: &mockArgs{ - userName: mockUserName1, - proxyReq: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID1, - }, - proxyResp: &seqapi.CancelAsyncSearchResponse{}, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, + req: &seqapi.CancelAsyncSearchRequest{ + SearchId: mockSearchID, }, + resp: &seqapi.CancelAsyncSearchResponse{}, }, - wantRespBody: ``, - wantStatus: http.StatusOK, }, { - name: "err_permission_denied", - mockArgs: &mockArgs{ - userName: mockUserName1, - proxyReq: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID1, - }, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID2, - OwnerName: mockUserName2, - }, - }, - wantRespBody: `{"message":"permission denied: cancel async search"}`, - wantStatus: http.StatusUnauthorized, + name: "invalid_id", + searchID: "some invalid id", + wantErr: true, }, { - name: "invalid id", + name: "err_svc", + searchID: mockSearchID, + wantErr: true, mockArgs: &mockArgs{ - userName: mockUserName1, - proxyReq: &seqapi.CancelAsyncSearchRequest{ - SearchId: "some_invalid_id", + req: &seqapi.CancelAsyncSearchRequest{ + SearchId: mockSearchID, }, + err: errSomethingWrong, }, - wantRespBody: `{"message":"invalid request field: invalid uuid"}`, - wantStatus: http.StatusBadRequest, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -118,45 +66,26 @@ func TestServeCancelAsyncSearch(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) - if tt.mockArgs.proxyResp != nil { - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().CancelAsyncSearch(gomock.Any(), tt.mockArgs.proxyReq). - Return(tt.mockArgs.proxyResp, tt.mockArgs.proxyErr).Times(1) - seqData.Mocks.SeqDB = seqDbMock + if tt.mockArgs.req != nil { + svcMock.EXPECT(). + CancelAsyncSearch(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - if tt.mockArgs.profilesResp != nil { - profilesRepoMock := mock_repo.NewMockUserProfiles(ctrl) - profilesRepoMock.EXPECT().GetOrCreate(gomock.Any(), *tt.mockArgs.profilesReq). - Return(*tt.mockArgs.profilesResp, tt.mockArgs.profilesErr).Times(1) - seqData.Mocks.ProfilesRepo = profilesRepoMock - } - - if tt.mockArgs.repoResp != nil { - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchById(gomock.Any(), tt.mockArgs.proxyReq.SearchId). - Return(*tt.mockArgs.repoResp, tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock - } + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - req := httptest.NewRequest( - http.MethodPost, - fmt.Sprintf("/seqapi/v1/async_search/%s/cancel", tt.mockArgs.proxyReq.SearchId), - http.NoBody, - ) - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, tt.mockArgs.userName)) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("id", tt.mockArgs.proxyReq.SearchId) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) - - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveCancelAsyncSearch, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + api := setupAPIWithAsyncSearches(seqData) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ + Method: http.MethodPost, + Target: fmt.Sprintf("/seqapi/v1/async_search/%s/cancel", mockSearchID), + Handler: withAsyncSearchID(api.serveCancelAsyncSearch, tt.searchID), + WantErr: tt.wantErr, + NoResp: tt.noResp, }) }) } @@ -164,17 +93,12 @@ func TestServeCancelAsyncSearch(t *testing.T) { func TestServeCancelAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) - req := httptest.NewRequest( - http.MethodPost, - "/seqapi/v1/async_search/c9a34cf8-4c66-484e-9cc2-42979d848656/cancel", - http.NoBody, - ) - - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveCancelAsyncSearch, - WantRespBody: `{"message":"async searches disabled"}`, - WantStatus: http.StatusBadRequest, + api := setupAPI(seqData) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/c9a34cf8-4c66-484e-9cc2-42979d848656/cancel", + Handler: api.serveCancelAsyncSearch, + WantErr: true, }) } diff --git a/internal/api/seqapi/v1/http/cluster_status_test.go b/internal/api/seqapi/v1/http/cluster_status_test.go index 448345e..931406f 100644 --- a/internal/api/seqapi/v1/http/cluster_status_test.go +++ b/internal/api/seqapi/v1/http/cluster_status_test.go @@ -1,11 +1,8 @@ package http import ( - "errors" "net/http" - "net/http/httptest" "testing" - "time" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -22,21 +19,27 @@ func TestStatus(t *testing.T) { err error } - type testCase struct { + tests := []struct { name string - wantRespBody string - wantStatus int + want statusResponse + wantErr bool - mockArgs mockArgs - } - - someMoment := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) - - tests := []testCase{ + mockArgs *mockArgs + }{ { name: "ok", - mockArgs: mockArgs{ + want: statusResponse{ + OldestStorageTime: &someMoment, + NumberOfStores: 1, + Stores: []storeStatus{ + { + Host: "host-0", + Values: &storeStatusValues{OldestTime: &someMoment}, + }, + }, + }, + mockArgs: &mockArgs{ resp: &seqapi.StatusResponse{ NumberOfStores: 1, OldestStorageTime: timestamppb.New(someMoment), @@ -48,38 +51,38 @@ func TestStatus(t *testing.T) { }, }, }, - wantRespBody: `{"oldest_storage_time":"2020-01-01T00:00:00Z","number_of_stores":1,"stores":[{"host":"host-0","values":{"oldest_time":"2020-01-01T00:00:00Z"}}]}`, - wantStatus: http.StatusOK, }, { - name: "err_client", - mockArgs: mockArgs{ - err: errors.New("client error"), + name: "err_client", + wantErr: true, + mockArgs: &mockArgs{ + err: errSomethingWrong, }, - wantStatus: http.StatusInternalServerError, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) seqData := test.APITestData{} - + ctrl := gomock.NewController(t) seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().Status(gomock.Any(), gomock.Any()). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - seqData.Mocks.SeqDB = seqDbMock - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodGet, "/seqapi/v1/status", http.NoBody) + seqDbMock.EXPECT(). + Status(gomock.Any(), gomock.Any()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + + seqData.Mocks.SeqDB = seqDbMock + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveStatus, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, statusResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/status", + Handler: api.serveStatus, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/seqapi/v1/http/delete_async_search.go b/internal/api/seqapi/v1/http/delete_async_search.go index addf2b9..28e64a7 100644 --- a/internal/api/seqapi/v1/http/delete_async_search.go +++ b/internal/api/seqapi/v1/http/delete_async_search.go @@ -47,15 +47,7 @@ func (a *API) serveDeleteAsyncSearch(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - - _, err = a.asyncSearches.DeleteAsyncSearch(ctx, profileID, &seqapi.DeleteAsyncSearchRequest{ - SearchId: searchID, - }) + _, err := a.asyncSearches.DeleteAsyncSearch(ctx, &seqapi.DeleteAsyncSearchRequest{SearchId: searchID}) if err != nil { status := http.StatusInternalServerError if errors.Is(err, types.ErrPermissionDenied) { diff --git a/internal/api/seqapi/v1/http/delete_async_search_test.go b/internal/api/seqapi/v1/http/delete_async_search_test.go index 878adf6..adec54b 100644 --- a/internal/api/seqapi/v1/http/delete_async_search_test.go +++ b/internal/api/seqapi/v1/http/delete_async_search_test.go @@ -1,119 +1,63 @@ package http import ( - "context" "fmt" "net/http" - "net/http/httptest" "testing" - "github.com/go-chi/chi/v5" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" - "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeDeleteAsyncSearch(t *testing.T) { - const ( - mockSearchID1 = "69e4a4a6-0922-43bd-952d-060a86c2b622" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - mockProfileID1 = 1 - mockProfileID2 = 2 - ) - type mockArgs struct { - userName string - - proxyReq *seqapi.DeleteAsyncSearchRequest - proxyResp *seqapi.DeleteAsyncSearchResponse - proxyErr error - - profilesReq *types.GetOrCreateUserProfileRequest - profilesResp *types.UserProfile - profilesErr error - - repoGetAsyncSearchResp *types.AsyncSearchInfo - repoGetAsyncSearchErr error - - repoDeleteAsyncSearchErr error + req *seqapi.DeleteAsyncSearchRequest + resp *seqapi.DeleteAsyncSearchResponse + err error } tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int - shouldDelete bool + searchID string + wantErr bool + noResp bool mockArgs *mockArgs }{ { - name: "ok", + name: "ok", + searchID: mockSearchID, + noResp: true, mockArgs: &mockArgs{ - userName: mockUserName1, - proxyReq: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID1, - }, - proxyResp: &seqapi.DeleteAsyncSearchResponse{}, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoGetAsyncSearchResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, + req: &seqapi.DeleteAsyncSearchRequest{ + SearchId: mockSearchID, }, + resp: &seqapi.DeleteAsyncSearchResponse{}, }, - shouldDelete: true, - wantRespBody: ``, - wantStatus: http.StatusOK, }, { - name: "err_permission_denied", - mockArgs: &mockArgs{ - userName: mockUserName1, - proxyReq: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID1, - }, - profilesReq: &types.GetOrCreateUserProfileRequest{ - UserName: mockUserName1, - }, - profilesResp: &types.UserProfile{ - ID: mockProfileID1, - UserName: mockUserName1, - }, - repoGetAsyncSearchResp: &types.AsyncSearchInfo{ - SearchID: mockSearchID1, - OwnerID: mockProfileID2, - OwnerName: mockUserName2, - }, - }, - wantRespBody: `{"message":"permission denied: delete async search"}`, - wantStatus: http.StatusUnauthorized, + name: "invalid_id", + searchID: "some invalid id", + wantErr: true, }, { - name: "invalid id", + name: "err_svc", + searchID: mockSearchID, + wantErr: true, mockArgs: &mockArgs{ - userName: mockUserName1, - proxyReq: &seqapi.DeleteAsyncSearchRequest{ - SearchId: "some_invalid_id", + req: &seqapi.DeleteAsyncSearchRequest{ + SearchId: mockSearchID, }, + err: errSomethingWrong, }, - wantRespBody: `{"message":"invalid request field: invalid uuid"}`, - wantStatus: http.StatusBadRequest, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -123,50 +67,23 @@ func TestServeDeleteAsyncSearch(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) - if tt.mockArgs.proxyResp != nil { - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().DeleteAsyncSearch(gomock.Any(), tt.mockArgs.proxyReq). - Return(tt.mockArgs.proxyResp, tt.mockArgs.proxyErr).Times(1) - seqData.Mocks.SeqDB = seqDbMock - } - - if tt.mockArgs.profilesResp != nil { - profilesRepoMock := mock_repo.NewMockUserProfiles(ctrl) - profilesRepoMock.EXPECT().GetOrCreate(gomock.Any(), *tt.mockArgs.profilesReq). - Return(*tt.mockArgs.profilesResp, tt.mockArgs.profilesErr).Times(1) - seqData.Mocks.ProfilesRepo = profilesRepoMock - } - - if tt.mockArgs.repoGetAsyncSearchResp != nil { - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchById(gomock.Any(), tt.mockArgs.proxyReq.SearchId). - Return(*tt.mockArgs.repoGetAsyncSearchResp, tt.mockArgs.repoGetAsyncSearchErr).Times(1) - - if tt.shouldDelete { - asyncSearchesRepoMock.EXPECT().DeleteAsyncSearch(gomock.Any(), tt.mockArgs.proxyReq.SearchId). - Return(tt.mockArgs.repoDeleteAsyncSearchErr).Times(1) - } - - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock - } + svcMock := mock_asyncsearches.NewMockService(ctrl) + svcMock.EXPECT(). + DeleteAsyncSearch(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - req := httptest.NewRequest( - http.MethodDelete, - fmt.Sprintf("/seqapi/v1/async_search/%s", tt.mockArgs.proxyReq.SearchId), - http.NoBody, - ) - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, tt.mockArgs.userName)) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("id", tt.mockArgs.proxyReq.SearchId) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) - - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveDeleteAsyncSearch, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + api := setupAPIWithAsyncSearches(seqData) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ + Method: http.MethodDelete, + Target: fmt.Sprintf("/seqapi/v1/async_search/%s", mockSearchID), + Handler: withAsyncSearchID(api.serveDeleteAsyncSearch, tt.searchID), + WantErr: tt.wantErr, + NoResp: tt.noResp, }) }) } @@ -174,17 +91,12 @@ func TestServeDeleteAsyncSearch(t *testing.T) { func TestServeDeleteAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) - req := httptest.NewRequest( - http.MethodDelete, - "/seqapi/v1/async_search/c9a34cf8-4c66-484e-9cc2-42979d848656", - http.NoBody, - ) - - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveDeleteAsyncSearch, - WantRespBody: `{"message":"async searches disabled"}`, - WantStatus: http.StatusBadRequest, + api := setupAPI(seqData) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ + Method: http.MethodDelete, + Target: "/seqapi/v1/async_search/c9a34cf8-4c66-484e-9cc2-42979d848656", + Handler: api.serveDeleteAsyncSearch, + WantErr: true, }) } diff --git a/internal/api/seqapi/v1/http/events_test.go b/internal/api/seqapi/v1/http/events_test.go index 5646dbf..78f4d4e 100644 --- a/internal/api/seqapi/v1/http/events_test.go +++ b/internal/api/seqapi/v1/http/events_test.go @@ -1,16 +1,11 @@ package http import ( - "context" - "encoding/json" "errors" "fmt" "net/http" - "net/http/httptest" "testing" - "time" - "github.com/go-chi/chi/v5" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" "google.golang.org/protobuf/proto" @@ -25,45 +20,39 @@ import ( ) func TestServeGetEvent(t *testing.T) { - type seqDBArgs struct { + event1 := test.MakeEvent(id1, 1, someMoment) + event1json, _ := proto.Marshal(event1) + event2 := test.MakeEvent(id2, 2, someMoment) + event2json, _ := proto.Marshal(event2) + event3 := test.MakeEvent(id3, 0, someMoment) + event3json, _ := proto.Marshal(event3) + + type mockArgs struct { req *seqapi.GetEventRequest resp *seqapi.GetEventResponse err error } - eventTime := time.Date(2024, time.December, 31, 10, 20, 30, 400000, time.UTC) // 2024-12-31T10:20:30.0004Z - id1 := "test1" - id2 := "test2" - id3 := "test3" - id4 := "test4" - event1 := test.MakeEvent(id1, 1, eventTime) - event1json, _ := proto.Marshal(event1) - event2 := test.MakeEvent(id2, 2, eventTime) - event2json, _ := proto.Marshal(event2) - event3 := test.MakeEvent(id3, 0, eventTime) - event3json, _ := proto.Marshal(event3) - err := errors.New("test error") - cacheTTL := time.Minute - tests := []struct { name string - id string - wantRespBody string - wantStatus int + id string + want getEventResponse + wantErr bool cacheArgs test.CacheMockArgs - seqDBArgs *seqDBArgs + mockArgs *mockArgs }{ { name: "ok_no_cached", id: id1, + want: getEventResponse{Event: eventFromProto(event1)}, cacheArgs: test.CacheMockArgs{ Key: id1, Value: string(event1json), - Err: err, + Err: errSomethingWrong, }, - seqDBArgs: &seqDBArgs{ + mockArgs: &mockArgs{ req: &seqapi.GetEventRequest{ Id: id1, }, @@ -71,28 +60,26 @@ func TestServeGetEvent(t *testing.T) { Event: event1, }, }, - wantRespBody: `{"event":{"id":"test1","data":{"field1":"val1"},"time":"2024-12-31T10:20:30.0004Z"}}`, - wantStatus: http.StatusOK, }, { name: "ok_cached", id: id2, + want: getEventResponse{Event: eventFromProto(event2)}, cacheArgs: test.CacheMockArgs{ Key: id2, Value: string(event2json), }, - wantRespBody: `{"event":{"id":"test2","data":{"field1":"val1","field2":"val2"},"time":"2024-12-31T10:20:30.0004Z"}}`, - wantStatus: http.StatusOK, }, { name: "ok_empty", id: id3, + want: getEventResponse{Event: eventFromProto(event3)}, cacheArgs: test.CacheMockArgs{ Key: id3, Value: string(event3json), - Err: err, + Err: errSomethingWrong, }, - seqDBArgs: &seqDBArgs{ + mockArgs: &mockArgs{ req: &seqapi.GetEventRequest{ Id: id3, }, @@ -100,31 +87,29 @@ func TestServeGetEvent(t *testing.T) { Event: event3, }, }, - wantRespBody: `{"event":{"id":"test3","data":{},"time":"2024-12-31T10:20:30.0004Z"}}`, - wantStatus: http.StatusOK, }, { - name: "err_client", - id: id4, + name: "err_client", + id: id4, + wantErr: true, cacheArgs: test.CacheMockArgs{ Key: id4, - Err: err, + Err: errSomethingWrong, }, - seqDBArgs: &seqDBArgs{ + mockArgs: &mockArgs{ req: &seqapi.GetEventRequest{ Id: id4, }, err: errors.New("client error"), }, - wantStatus: http.StatusInternalServerError, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) + ctrl := gomock.NewController(t) seqData := test.APITestData{ Cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ @@ -134,55 +119,53 @@ func TestServeGetEvent(t *testing.T) { } cacheMock := mock_cache.NewMockCache(ctrl) - cacheMock.EXPECT().Get(gomock.Any(), tt.cacheArgs.Key). - Return(tt.cacheArgs.Value, tt.cacheArgs.Err).Times(1) + cacheMock.EXPECT(). + Get(gomock.Any(), tt.cacheArgs.Key). + Return(tt.cacheArgs.Value, tt.cacheArgs.Err). + Times(1) seqData.Mocks.Cache = cacheMock - if tt.seqDBArgs != nil { + if tt.mockArgs != nil { seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetEvent(gomock.Any(), tt.seqDBArgs.req). - Return(tt.seqDBArgs.resp, tt.seqDBArgs.err).Times(1) + seqDbMock.EXPECT(). + GetEvent(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) seqData.Mocks.SeqDB = seqDbMock - if tt.seqDBArgs.err == nil { - cacheMock.EXPECT().SetWithTTL(gomock.Any(), tt.cacheArgs.Key, tt.cacheArgs.Value, cacheTTL). - Return(nil).Times(1) + if tt.mockArgs.err == nil { + cacheMock.EXPECT(). + SetWithTTL(gomock.Any(), tt.cacheArgs.Key, tt.cacheArgs.Value, cacheTTL). + Return(nil). + Times(1) } } - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/seqapi/v1/events/%s", tt.id), http.NoBody) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("id", tt.id) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetEvent, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getEventResponse]{ + Method: http.MethodGet, + Target: fmt.Sprintf("/seqapi/v1/events/%s", tt.id), + Handler: withEventID(api.serveGetEvent, tt.id), + Want: tt.want, + WantErr: tt.wantErr, }) }) } } func TestGetEventWithMasking(t *testing.T) { - type seqDBArgs struct { + type mockArgs struct { req *seqapi.GetEventRequest resp *seqapi.GetEventResponse } - eventTime := time.Date(2024, time.December, 31, 10, 20, 30, 400000, time.UTC) // 2024-12-31T10:20:30.0004Z - - cacheErr := errors.New("test error") - cacheTTL := time.Minute - tests := []struct { name string shouldMask bool isCached bool - wantStatus int + wantErr bool maskingCfg *config.Masking }{ @@ -190,7 +173,6 @@ func TestGetEventWithMasking(t *testing.T) { name: "mask_noncached", shouldMask: true, isCached: false, - wantStatus: http.StatusOK, maskingCfg: &config.Masking{ Masks: []config.Mask{ { @@ -216,7 +198,6 @@ func TestGetEventWithMasking(t *testing.T) { name: "mask_from_cache", shouldMask: true, isCached: true, - wantStatus: http.StatusOK, maskingCfg: &config.Masking{ Masks: []config.Mask{ { @@ -242,7 +223,6 @@ func TestGetEventWithMasking(t *testing.T) { name: "do_not_mask_noncached_regex", shouldMask: false, isCached: false, - wantStatus: http.StatusOK, maskingCfg: &config.Masking{ Masks: []config.Mask{ { @@ -268,7 +248,6 @@ func TestGetEventWithMasking(t *testing.T) { name: "do_not_mask_from_cache_regex", shouldMask: false, isCached: true, - wantStatus: http.StatusOK, maskingCfg: &config.Masking{ Masks: []config.Mask{ { @@ -294,7 +273,6 @@ func TestGetEventWithMasking(t *testing.T) { name: "do_not_mask_noncached_field_filter", shouldMask: false, isCached: true, - wantStatus: http.StatusOK, maskingCfg: &config.Masking{ Masks: []config.Mask{ { @@ -320,7 +298,6 @@ func TestGetEventWithMasking(t *testing.T) { name: "do_not_mask_from_cache_field_filter", shouldMask: false, isCached: true, - wantStatus: http.StatusOK, maskingCfg: &config.Masking{ Masks: []config.Mask{ { @@ -348,7 +325,7 @@ func TestGetEventWithMasking(t *testing.T) { id string event *seqapi.Event eventJson []byte - wantResp []byte + want getEventResponse } formEventData := func(i int, shouldMask bool) eventData { @@ -361,20 +338,18 @@ func TestGetEventWithMasking(t *testing.T) { Data: map[string]string{ eventField: eventVal, }, - Time: timestamppb.New(eventTime), + Time: timestamppb.New(someMoment), } if shouldMask { event.Data[eventField] = "***" } eventJson, err := proto.Marshal(event) require.NoError(t, err) - wantResp, err := json.Marshal(getEventResponse{Event: eventFromProto(event)}) - require.NoError(t, err) return eventData{ id: id, event: event, eventJson: eventJson, - wantResp: wantResp, + want: getEventResponse{Event: eventFromProto(event)}, } } @@ -384,12 +359,10 @@ func TestGetEventWithMasking(t *testing.T) { } for i, tt := range tests { - i := i - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) + ctrl := gomock.NewController(t) curEData := eventsData[i] curEID := curEData.id @@ -408,40 +381,46 @@ func TestGetEventWithMasking(t *testing.T) { Value: string(curEData.eventJson), } if !tt.isCached { - cacheArgs.Err = cacheErr + cacheArgs.Err = errCache } - cacheMock.EXPECT().Get(gomock.Any(), cacheArgs.Key). - Return(cacheArgs.Value, cacheArgs.Err).Times(1) + cacheMock.EXPECT(). + Get(gomock.Any(), cacheArgs.Key). + Return(cacheArgs.Value, cacheArgs.Err). + Times(1) seqData.Mocks.Cache = cacheMock seqDbMock := mock_seqdb.NewMockClient(ctrl) if !tt.isCached { - seqDBArgs := &seqDBArgs{ + mockArgs := &mockArgs{ req: &seqapi.GetEventRequest{Id: curEData.id}, resp: &seqapi.GetEventResponse{Event: curEData.event}, } - seqDbMock.EXPECT().GetEvent(gomock.Any(), seqDBArgs.req). - Return(seqDBArgs.resp, nil).Times(1) + seqDbMock.EXPECT(). + GetEvent(gomock.Any(), mockArgs.req). + Return(mockArgs.resp, nil). + Times(1) - cacheMock.EXPECT().SetWithTTL(gomock.Any(), cacheArgs.Key, cacheArgs.Value, cacheTTL). - Return(nil).Times(1) + cacheMock.EXPECT(). + SetWithTTL(gomock.Any(), cacheArgs.Key, cacheArgs.Value, cacheTTL). + Return(nil). + Times(1) } if tt.maskingCfg != nil { - seqDbMock.EXPECT().WithMasking(gomock.Any()).Return().Times(1) + seqDbMock.EXPECT(). + WithMasking(gomock.Any()). + Return(). + Times(1) } seqData.Mocks.SeqDB = seqDbMock - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/seqapi/v1/events/%s", curEID), http.NoBody) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("id", curEID) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetEvent, - WantRespBody: string(curEData.wantResp), - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getEventResponse]{ + Method: http.MethodGet, + Target: fmt.Sprintf("/seqapi/v1/events/%s", curEID), + Handler: withEventID(api.serveGetEvent, curEID), + Want: curEData.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/seqapi/v1/http/export_test.go b/internal/api/seqapi/v1/http/export_test.go index 0b339fc..5ccb91e 100644 --- a/internal/api/seqapi/v1/http/export_test.go +++ b/internal/api/seqapi/v1/http/export_test.go @@ -1,17 +1,9 @@ package http import ( - "encoding/json" - "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" - "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -23,28 +15,6 @@ import ( ) func TestServeExport(t *testing.T) { - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(time.Second) - - formatReqBody := func(limit int, format exportFormat, fields []string) string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"offset":0,"limit":%d`, - query, from.Format(time.RFC3339), to.Format(time.RFC3339), limit)) - - if format != "" { - sb.WriteString(fmt.Sprintf(`,"format":%q`, format)) - } - if len(fields) > 0 { - fieldsRaw, err := json.Marshal(fields) - assert.NoError(t, err) - sb.WriteString(fmt.Sprintf(`,"fields":%s`, fieldsRaw)) - } - - sb.WriteString("}") - return sb.String() - } - type mockArgs struct { req *seqapi.ExportRequest err error @@ -53,15 +23,27 @@ func TestServeExport(t *testing.T) { tests := []struct { name string - reqBody string - wantStatus int + req exportRequest + cfg config.SeqAPI + wantErr bool mockArgs *mockArgs - cfg config.SeqAPI }{ { - name: "ok_jsonl", - reqBody: formatReqBody(50, "", nil), + name: "ok_jsonl", + req: exportRequest{ + Query: query, + From: from, + To: to, + Limit: 50, + Offset: 0, + }, + cfg: config.SeqAPI{ + SeqAPIOptions: &config.SeqAPIOptions{ + MaxExportLimit: 100, + MaxParallelExportRequests: 1, + }, + }, mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ Query: query, @@ -71,17 +53,24 @@ func TestServeExport(t *testing.T) { Offset: 0, }, }, - wantStatus: http.StatusOK, + }, + { + name: "ok_csv", + req: exportRequest{ + Query: query, + From: from, + To: to, + Limit: 50, + Offset: 0, + Format: efCSV, + Fields: []string{"field1", "field2"}, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxExportLimit: 100, MaxParallelExportRequests: 1, }, }, - }, - { - name: "ok_csv", - reqBody: formatReqBody(50, efCSV, []string{"field1", "field2"}), mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ Query: query, @@ -93,54 +82,74 @@ func TestServeExport(t *testing.T) { Fields: []string{"field1", "field2"}, }, }, - wantStatus: http.StatusOK, - cfg: config.SeqAPI{ - SeqAPIOptions: &config.SeqAPIOptions{ - MaxExportLimit: 100, - MaxParallelExportRequests: 1, - }, - }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - }, - { - name: "err_parallel_limited", - reqBody: formatReqBody(0, "", nil), - wantStatus: http.StatusTooManyRequests, + name: "err_parallel_limited", + req: exportRequest{ + Query: query, + From: from, + To: to, + Limit: 0, + Offset: 0, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxParallelExportRequests: 0, }, }, + wantErr: true, }, { - name: "err_export_limit_max", - reqBody: formatReqBody(10, "", nil), - wantStatus: http.StatusBadRequest, + name: "err_export_limit_max", + req: exportRequest{ + Query: query, + From: from, + To: to, + Limit: 10, + Offset: 0, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxExportLimit: 5, MaxParallelExportRequests: 1, }, }, + wantErr: true, }, { - name: "err_csv_empty_fields", - reqBody: formatReqBody(10, efCSV, nil), - wantStatus: http.StatusBadRequest, + name: "err_csv_empty_fields", + req: exportRequest{ + Query: query, + From: from, + To: to, + Limit: 10, + Offset: 0, + Format: efCSV, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxExportLimit: 100, MaxParallelExportRequests: 1, }, }, + wantErr: true, }, { - name: "err_client", - reqBody: formatReqBody(50, "", nil), + name: "err_client", + req: exportRequest{ + Query: query, + From: from, + To: to, + Limit: 50, + Offset: 0, + }, + cfg: config.SeqAPI{ + SeqAPIOptions: &config.SeqAPIOptions{ + MaxExportLimit: 100, + MaxParallelExportRequests: 1, + }, + }, + wantErr: true, mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ Query: query, @@ -149,19 +158,12 @@ func TestServeExport(t *testing.T) { Limit: 50, Offset: 0, }, - err: errors.New("client error"), - }, - wantStatus: http.StatusInternalServerError, - cfg: config.SeqAPI{ - SeqAPIOptions: &config.SeqAPIOptions{ - MaxExportLimit: 100, - MaxParallelExportRequests: 1, - }, + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -169,28 +171,28 @@ func TestServeExport(t *testing.T) { Cfg: tt.cfg, } - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/export", strings.NewReader(tt.reqBody)) - w := httptest.NewRecorder() - if tt.mockArgs != nil { ctrl := gomock.NewController(t) seqDbMock := mock_seqdb.NewMockClient(ctrl) - cw, _ := httputil.NewChunkedWriter(w) - seqDbMock.EXPECT().Export(gomock.Any(), tt.mockArgs.req, cw). - Return(tt.mockArgs.err).Times(1) + seqDbMock.EXPECT(). + Export(gomock.Any(), tt.mockArgs.req, gomock.Any()). + Return(tt.mockArgs.err). + Times(1) seqData.Mocks.SeqDB = seqDbMock } - s := initTestAPI(seqData) - - s.serveExport(w, req) - - res := w.Result() - defer res.Body.Close() + api := setupAPI(seqData) - require.Equal(t, tt.wantStatus, res.StatusCode) + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[exportRequest, struct{}]{ + Method: http.MethodPost, + Target: "/seqapi/v1/export", + Req: tt.req, + Handler: api.serveExport, + WantErr: tt.wantErr, + NoResp: true, + }) }) } } diff --git a/internal/api/seqapi/v1/http/fetch_async_search_result_test.go b/internal/api/seqapi/v1/http/fetch_async_search_result_test.go index c884917..fe7660b 100644 --- a/internal/api/seqapi/v1/http/fetch_async_search_result_test.go +++ b/internal/api/seqapi/v1/http/fetch_async_search_result_test.go @@ -2,8 +2,6 @@ package http import ( "net/http" - "net/http/httptest" - "strings" "testing" "time" @@ -13,54 +11,163 @@ import ( "github.com/ozontech/seq-ui/internal/api/httputil" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" - "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeFetchAsyncSearchResult(t *testing.T) { - var ( - mockSearchID = "c9a34cf8-4c66-484e-9cc2-42979d848656" - mockTime = time.Date(2025, 8, 6, 17, 52, 12, 123, time.UTC) - meta = `{"some":"meta"}` - ) - type mockArgs struct { - proxyReq *seqapi.FetchAsyncSearchResultRequest - proxyResp *seqapi.FetchAsyncSearchResultResponse - proxyErr error - - repoResp types.AsyncSearchInfo - repoErr error + req *seqapi.FetchAsyncSearchResultRequest + resp *seqapi.FetchAsyncSearchResultResponse + err error } tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req fetchAsyncSearchResultRequest + want fetchAsyncSearchResultResponse + wantErr bool mockArgs *mockArgs }{ { - name: "ok", - reqBody: `{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","limit":2,"offset":10,"order":"desc"}`, + name: "ok", + req: fetchAsyncSearchResultRequest{ + SearchID: mockSearchID, + Limit: 2, + Offset: 10, + Order: oDESC, + }, + want: fetchAsyncSearchResultResponseFromProto(&seqapi.FetchAsyncSearchResultResponse{ + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: "message:error", + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), + Aggs: []*seqapi.AggregationQuery{ + { + Field: "x", + GroupBy: "level", + Func: seqapi.AggFunc_AGG_FUNC_AVG, + Quantiles: []float64{0.9, 0.5}, + }, + { + Field: "y", + GroupBy: "level", + Func: seqapi.AggFunc_AGG_FUNC_SUM, + Interval: pointerTo("30s"), + }, + }, + Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ + Interval: "1s", + }, + WithDocs: true, + Size: 100, + }, + Response: &seqapi.SearchResponse{ + Events: []*seqapi.Event{ + { + Id: "017a854298010000-850287cfa326a7fc", + Data: map[string]string{ + "level": "3", + "message": "some error", + "x": "2", + }, + Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + }, + { + Id: "017a854298010000-8502fe7f2aa33df3", + Data: map[string]string{ + "level": "2", + "message": "some error 2", + "x": "8", + }, + Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + }, + }, + Total: 2, + Histogram: &seqapi.Histogram{ + Buckets: []*seqapi.Histogram_Bucket{ + { + DocCount: 7, + Key: 1, + }, + { + DocCount: 9, + Key: 2, + }, + }, + }, + Aggregations: []*seqapi.Aggregation{ + { + Buckets: []*seqapi.Aggregation_Bucket{ + { + Key: "3", + Value: pointerTo[float64](2), + NotExists: 0, + Quantiles: []float64{2, 1}, + }, + { + Key: "2", + Value: pointerTo[float64](8), + NotExists: 1, + Quantiles: []float64{7, 4}, + }, + }, + }, + { + Buckets: []*seqapi.Aggregation_Bucket{ + { + Key: "33", + Value: pointerTo[float64](2), + NotExists: 0, + Ts: timestamppb.New(someMoment.Add(-30 * time.Second)), + }, + { + Key: "33", + Value: pointerTo[float64](5), + NotExists: 0, + Ts: timestamppb.New(someMoment), + }, + { + Key: "22", + Value: pointerTo[float64](8), + NotExists: 1, + Ts: timestamppb.New(someMoment.Add(-1 * time.Minute)), + }, + }, + NotExists: 2, + }, + }, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_UNSPECIFIED, + Message: "some error", + }, + }, + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + Progress: 1, + DiskUsage: 512, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_NO, + }, + }), mockArgs: &mockArgs{ - proxyReq: &seqapi.FetchAsyncSearchResultRequest{ + req: &seqapi.FetchAsyncSearchResultRequest{ SearchId: mockSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, }, - proxyResp: &seqapi.FetchAsyncSearchResultResponse{ + resp: &seqapi.FetchAsyncSearchResultResponse{ Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -90,7 +197,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(mockTime.Add(-1 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -99,7 +206,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(mockTime.Add(-2 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -138,19 +245,19 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Key: "33", Value: pointerTo[float64](2), NotExists: 0, - Ts: timestamppb.New(mockTime.Add(-30 * time.Second)), + Ts: timestamppb.New(someMoment.Add(-30 * time.Second)), }, { Key: "33", Value: pointerTo[float64](5), NotExists: 0, - Ts: timestamppb.New(mockTime), + Ts: timestamppb.New(someMoment), }, { Key: "22", Value: pointerTo[float64](8), NotExists: 1, - Ts: timestamppb.New(mockTime.Add(-1 * time.Minute)), + Ts: timestamppb.New(someMoment.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -161,39 +268,84 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - repoResp: types.AsyncSearchInfo{ - SearchID: mockSearchID, - Meta: meta, - }, }, - wantRespBody: `{"status":"done","request":{"retention":"seconds:60","query":"message:error","from":"2025-08-06T17:37:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","aggregations":[{"field":"x","group_by":"level","agg_func":"avg","quantiles":[0.9,0.5]},{"field":"y","group_by":"level","agg_func":"sum","interval":"30s"}],"histogram":{"interval":"1s"},"with_docs":true,"size":100},"response":{"events":[{"id":"017a854298010000-850287cfa326a7fc","data":{"level":"3","message":"some error","x":"2"},"time":"2025-08-06T17:51:12.000000123Z"},{"id":"017a854298010000-8502fe7f2aa33df3","data":{"level":"2","message":"some error 2","x":"8"},"time":"2025-08-06T17:50:12.000000123Z"}],"histogram":{"buckets":[{"key":"1","docCount":"7"},{"key":"2","docCount":"9"}]},"aggregations":[{"buckets":[{"key":"3","value":2,"quantiles":[2,1]},{"key":"2","value":8,"not_exists":1,"quantiles":[7,4]}]}],"aggregations_ts":[{"data":{"result":[{"metric":{"level":"33"},"values":[{"timestamp":1754502702,"value":2},{"timestamp":1754502732,"value":5}]},{"metric":{"level":"22"},"values":[{"timestamp":1754502672,"value":8}]}]}}],"total":"2","error":{"code":"ERROR_CODE_UNSPECIFIED","message":"some error"}},"started_at":"2025-08-06T17:51:42.000000123Z","expires_at":"2025-08-06T17:52:42.000000123Z","progress":1,"disk_usage":"512","meta":"{\"some\":\"meta\"}","error":{"code":"ERROR_CODE_NO"}}`, - wantStatus: http.StatusOK, }, { - name: "partial_response", - reqBody: `{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","limit":2,"offset":10,"order":"desc"}`, + name: "partial_response", + req: fetchAsyncSearchResultRequest{ + SearchID: mockSearchID, + Limit: 2, + Offset: 10, + Order: oDESC, + }, + want: fetchAsyncSearchResultResponseFromProto(&seqapi.FetchAsyncSearchResultResponse{ + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: "message:error", + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), + WithDocs: true, + Size: 100, + }, + Response: &seqapi.SearchResponse{ + Events: []*seqapi.Event{ + { + Id: "017a854298010000-850287cfa326a7fc", + Data: map[string]string{ + "level": "3", + "message": "some error", + "x": "2", + }, + Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + }, + { + Id: "017a854298010000-8502fe7f2aa33df3", + Data: map[string]string{ + "level": "2", + "message": "some error 2", + "x": "8", + }, + Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + }, + }, + Total: 2, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_UNSPECIFIED, + Message: "some error", + }, + }, + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + Progress: 1, + DiskUsage: 512, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_PARTIAL_RESPONSE, + Message: "partial response", + }, + }), mockArgs: &mockArgs{ - proxyReq: &seqapi.FetchAsyncSearchResultRequest{ + req: &seqapi.FetchAsyncSearchResultRequest{ SearchId: mockSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, }, - proxyResp: &seqapi.FetchAsyncSearchResultResponse{ + resp: &seqapi.FetchAsyncSearchResultResponse{ Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, @@ -206,7 +358,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(mockTime.Add(-1 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -215,7 +367,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(mockTime.Add(-2 * time.Minute)), + Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -224,8 +376,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -233,38 +385,35 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "partial response", }, }, - repoResp: types.AsyncSearchInfo{ - SearchID: mockSearchID, - Meta: meta, - }, }, - wantRespBody: `{"status":"done","request":{"retention":"seconds:60","query":"message:error","from":"2025-08-06T17:37:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","with_docs":true,"size":100},"response":{"events":[{"id":"017a854298010000-850287cfa326a7fc","data":{"level":"3","message":"some error","x":"2"},"time":"2025-08-06T17:51:12.000000123Z"},{"id":"017a854298010000-8502fe7f2aa33df3","data":{"level":"2","message":"some error 2","x":"8"},"time":"2025-08-06T17:50:12.000000123Z"}],"total":"2","error":{"code":"ERROR_CODE_UNSPECIFIED","message":"some error"}},"started_at":"2025-08-06T17:51:42.000000123Z","expires_at":"2025-08-06T17:52:42.000000123Z","progress":1,"disk_usage":"512","meta":"{\"some\":\"meta\"}","error":{"code":"ERROR_CODE_PARTIAL_RESPONSE","message":"partial response"}}`, - wantStatus: http.StatusOK, - }, - { - name: "err_limit", - reqBody: `{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","limit":-10,"offset":20}`, - wantRespBody: `{"message":"invalid request field: 'limit' must be non-negative"}`, - wantStatus: http.StatusBadRequest, }, { - name: "err_offset", - reqBody: `{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","limit":10,"offset":-20}`, - wantRespBody: `{"message":"invalid request field: 'offset' must be non-negative"}`, - wantStatus: http.StatusBadRequest, + name: "err_limit", + req: fetchAsyncSearchResultRequest{ + SearchID: mockSearchID, + Limit: -10, + Offset: 20, + }, + wantErr: true, }, { - name: "invalid id", - reqBody: `{"search_id":"some_invalid_id"}`, - wantRespBody: `{"message":"invalid request field: invalid uuid"}`, - wantStatus: http.StatusBadRequest, + name: "err_offset", + req: fetchAsyncSearchResultRequest{ + SearchID: mockSearchID, + Limit: 10, + Offset: -20, + }, + wantErr: true, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, + name: "invalid_id", + req: fetchAsyncSearchResultRequest{ + SearchID: "some invalid id", + }, + wantErr: true, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -273,26 +422,25 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchById(gomock.Any(), mockSearchID). - Return(tt.mockArgs.repoResp, tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock + svcMock.EXPECT(). + FetchAsyncSearchResult(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().FetchAsyncSearchResult(gomock.Any(), tt.mockArgs.proxyReq). - Return(tt.mockArgs.proxyResp, tt.mockArgs.proxyErr).Times(1) - seqData.Mocks.SeqDB = seqDbMock + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/fetch", strings.NewReader(tt.reqBody)) + api := setupAPIWithAsyncSearches(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveFetchAsyncSearchResult, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[fetchAsyncSearchResultRequest, fetchAsyncSearchResultResponse]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/fetch", + Req: tt.req, + Handler: api.serveFetchAsyncSearchResult, + Want: tt.want, + WantErr: tt.wantErr, }) }) } @@ -300,14 +448,13 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { func TestServeFetchAsyncSearchResult_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/fetch", strings.NewReader("{}")) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveFetchAsyncSearchResult, - WantRespBody: `{"message":"async searches disabled"}`, - WantStatus: http.StatusBadRequest, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[fetchAsyncSearchResultRequest, struct{}]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/fetch", + Handler: api.serveFetchAsyncSearchResult, + WantErr: true, }) } diff --git a/internal/api/seqapi/v1/http/fields_test.go b/internal/api/seqapi/v1/http/fields_test.go index a22b61f..bb312ef 100644 --- a/internal/api/seqapi/v1/http/fields_test.go +++ b/internal/api/seqapi/v1/http/fields_test.go @@ -1,16 +1,10 @@ package http import ( - "encoding/json" - "errors" - "io" "net/http" - "net/http/httptest" "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" @@ -31,14 +25,20 @@ func TestServeGetFields(t *testing.T) { cfg config.SeqAPIOptions - wantRespBody string - wantStatus int + want getFieldsResponse + wantErr bool - mockArgs mockArgs + mockArgs *mockArgs }{ { name: "ok", - mockArgs: mockArgs{ + want: getFieldsResponse{ + Fields: fields{ + {Name: "test_name1", Type: "keyword"}, + {Name: "test_name2", Type: "text"}, + }, + }, + mockArgs: &mockArgs{ resp: &seqapi.GetFieldsResponse{ Fields: []*seqapi.Field{ { @@ -52,12 +52,24 @@ func TestServeGetFields(t *testing.T) { }, }, }, - wantRespBody: `{"fields":[{"name":"test_name1","type":"keyword"},{"name":"test_name2","type":"text"}]}`, - wantStatus: http.StatusOK, }, { name: "ok_with_system_and_pinned_fields", - mockArgs: mockArgs{ + want: getFieldsResponse{ + Fields: fields{ + {Name: "test_name1", Type: "keyword"}, + {Name: "test_name2", Type: "text"}, + }, + SystemFields: fields{ + {Name: "field1", Type: "keyword"}, + {Name: "field2", Type: "text"}, + }, + PinnedFields: fields{ + {Name: "field3", Type: "keyword"}, + {Name: "field4", Type: "text"}, + }, + }, + mockArgs: &mockArgs{ resp: &seqapi.GetFieldsResponse{ Fields: []*seqapi.Field{ { @@ -81,19 +93,17 @@ func TestServeGetFields(t *testing.T) { {Name: "field4", Type: "text"}, }, }, - wantRespBody: `{"fields":[{"name":"test_name1","type":"keyword"},{"name":"test_name2","type":"text"}],"system_fields":[{"name":"field1","type":"keyword"},{"name":"field2","type":"text"}],"pinned_fields":[{"name":"field3","type":"keyword"},{"name":"field4","type":"text"}]}`, - wantStatus: http.StatusOK, }, { - name: "err_client", - mockArgs: mockArgs{ - err: errors.New("client error"), + name: "err_client", + wantErr: true, + mockArgs: &mockArgs{ + err: errSomethingWrong, }, - wantStatus: http.StatusInternalServerError, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) @@ -105,31 +115,34 @@ func TestServeGetFields(t *testing.T) { } seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetFields(gomock.Any(), gomock.Any()). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) + seqDbMock.EXPECT(). + GetFields(gomock.Any(), gomock.Any()). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) seqData.Mocks.SeqDB = seqDbMock - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodGet, "/seqapi/v1/fields", http.NoBody) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetFields, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/fields", + Handler: api.serveGetFields, + Want: tt.want, + WantErr: tt.wantErr, }) }) } } func TestServeGetFieldsCached(t *testing.T) { - type TestCase struct { - resp *seqapi.GetFieldsResponse - wantRespBody string - } + tests := []struct { + name string - tests := []TestCase{ + resp *seqapi.GetFieldsResponse + want getFieldsResponse + }{ { + name: "ok", resp: &seqapi.GetFieldsResponse{ Fields: []*seqapi.Field{ { @@ -142,9 +155,15 @@ func TestServeGetFieldsCached(t *testing.T) { }, }, }, - wantRespBody: `{"fields":[{"name":"n1","type":"keyword"},{"name":"n2","type":"text"}]}`, + want: getFieldsResponse{ + Fields: fields{ + {Name: "n1", Type: "keyword"}, + {Name: "n2", Type: "text"}, + }, + }, }, { + name: "another_ok", resp: &seqapi.GetFieldsResponse{ Fields: []*seqapi.Field{ { @@ -153,51 +172,55 @@ func TestServeGetFieldsCached(t *testing.T) { }, }, }, - wantRespBody: `{"fields":[{"name":"qwe","type":"keyword"}]}`, + want: getFieldsResponse{ + Fields: fields{ + {Name: "qwe", Type: "keyword"}, + }, + }, }, } - ctrl := gomock.NewController(t) - seqDbMock := mock_seqdb.NewMockClient(ctrl) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() - for _, testCase := range tests { - seqDbMock.EXPECT().GetFields(gomock.Any(), gomock.Any()). - Return(testCase.resp, nil).Times(1) - } + ctrl := gomock.NewController(t) + seqDbMock := mock_seqdb.NewMockClient(ctrl) - const ttl = 20 * time.Millisecond + seqDbMock.EXPECT(). + GetFields(gomock.Any(), gomock.Any()). + Return(tt.resp, nil). + Times(1) - seqData := test.APITestData{ - Cfg: config.SeqAPI{ - SeqAPIOptions: &config.SeqAPIOptions{ - FieldsCacheTTL: ttl, - }, - }, - Mocks: test.Mocks{ - SeqDB: seqDbMock, - }, - } + seqData := test.APITestData{ + Cfg: config.SeqAPI{ + SeqAPIOptions: &config.SeqAPIOptions{ + FieldsCacheTTL: ttl, + }, + }, + Mocks: test.Mocks{ + SeqDB: seqDbMock, + }, + } - api := initTestAPI(seqData) + api := setupAPI(seqData) - for _, testCase := range tests { - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: httptest.NewRequest(http.MethodGet, "/seqapi/v1/fields", http.NoBody), - Handler: api.serveGetFields, - WantRespBody: testCase.wantRespBody, - WantStatus: http.StatusOK, - }) + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/fields", + Handler: api.serveGetFields, + Want: tt.want, + }) - time.Sleep(ttl / 2) + time.Sleep(ttl / 2) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: httptest.NewRequest(http.MethodGet, "/seqapi/v1/fields", http.NoBody), - Handler: api.serveGetFields, - WantRespBody: testCase.wantRespBody, - WantStatus: http.StatusOK, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/fields", + Handler: api.serveGetFields, + Want: tt.want, + }) }) - - time.Sleep(ttl) } } @@ -205,8 +228,8 @@ func TestServeGetPinnedFields(t *testing.T) { tests := []struct { name string - fields []config.Field - wantRespBody string + fields []config.Field + want getFieldsResponse }{ { name: "ok", @@ -214,15 +237,16 @@ func TestServeGetPinnedFields(t *testing.T) { {Name: "field1", Type: "keyword"}, {Name: "field2", Type: "text"}, }, - wantRespBody: `{"fields":[{"name":"field1","type":"keyword"},{"name":"field2","type":"text"}]}`, - }, - { - name: "empty", - wantRespBody: `{"fields":[]}`, + want: getFieldsResponse{ + Fields: fields{ + {Name: "field1", Type: "keyword"}, + {Name: "field2", Type: "text"}, + }, + }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -234,27 +258,14 @@ func TestServeGetPinnedFields(t *testing.T) { }, } - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodGet, "/seqapi/v1/fields/pinned", http.NoBody) - w := httptest.NewRecorder() + api := setupAPI(seqData) - api.serveGetPinnedFields(w, req) - - resp := w.Result() - defer resp.Body.Close() - - respBody, err := io.ReadAll(resp.Body) - assert.NoError(t, err) - - var gfr getFieldsResponse - err = json.Unmarshal(respBody, &gfr) - assert.NoError(t, err) - - require.Equal(t, len(tt.fields), len(gfr.Fields)) - for i, f := range gfr.Fields { - require.Equal(t, tt.fields[i].Name, f.Name) - require.Equal(t, tt.fields[i].Type, f.Type) - } + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/fields/pinned", + Handler: api.serveGetPinnedFields, + Want: tt.want, + }) }) } } diff --git a/internal/api/seqapi/v1/http/get_async_searches_list_test.go b/internal/api/seqapi/v1/http/get_async_searches_list_test.go index 1811ae6..0ad5e72 100644 --- a/internal/api/seqapi/v1/http/get_async_searches_list_test.go +++ b/internal/api/seqapi/v1/http/get_async_searches_list_test.go @@ -2,8 +2,6 @@ package http import ( "net/http" - "net/http/httptest" - "strings" "testing" "time" @@ -13,68 +11,101 @@ import ( "github.com/ozontech/seq-ui/internal/api/httputil" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" - "github.com/ozontech/seq-ui/internal/app/config" - "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeGetAsyncSearchesList(t *testing.T) { - var ( - mockSearchID1 = "c9a34cf8-4c66-484e-9cc2-42979d848656" - mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - mockProfileID1 int64 = 1 - mockProfileID2 int64 = 1 - errorMsg = "some error" - tooLongQuery = strings.Repeat("message:error and level:3", 41) - TruncatedQuery = strings.Repeat("message:error and level:3", 40) - mockTime = time.Date(2025, 8, 6, 17, 52, 12, 123, time.UTC) - ) + statusDone := asyncSearchStatus("done") type mockArgs struct { - searchIDs []string - proxyReq *seqapi.GetAsyncSearchesListRequest - proxyResp *seqapi.GetAsyncSearchesListResponse - proxyErr error - - repoReq types.GetAsyncSearchesListRequest - repoResp []types.AsyncSearchInfo - repoErr error + req *seqapi.GetAsyncSearchesListRequest + resp *seqapi.GetAsyncSearchesListResponse + err error } tests := []struct { name string - reqBody string - cfg config.Handlers - wantRespBody string - wantStatus int + req getAsyncSearchesListRequest + want getAsyncSearchesListResponse + wantErr bool mockArgs *mockArgs }{ { - name: "ok_no_filters", - reqBody: `{}`, + name: "ok_no_filters", + req: getAsyncSearchesListRequest{}, + want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ + Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ + { + SearchId: mockSearchID, + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: "message:error", + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), + WithDocs: true, + Size: 100, + }, + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + Progress: 1, + DiskUsage: 512, + OwnerName: mockUserName1, + Error: &errorMsg, + }, + { + SearchId: mockSearchID2, + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_CANCELED, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(360 * time.Second), + Query: "message:error and level:3", + From: timestamppb.New(someMoment.Add(-1 * time.Hour)), + To: timestamppb.New(someMoment), + Aggs: []*seqapi.AggregationQuery{ + { + Field: "x", + GroupBy: "level", + Func: seqapi.AggFunc_AGG_FUNC_AVG, + Interval: pointerTo("30s"), + }, + }, + Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ + Interval: "1s", + }, + WithDocs: false, + }, + StartedAt: timestamppb.New(someMoment.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(300 * time.Second)), + CanceledAt: timestamppb.New(someMoment), + Progress: 1, + DiskUsage: 256, + OwnerName: mockUserName2, + }, + }, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_NO, + }, + }), mockArgs: &mockArgs{ - proxyReq: &seqapi.GetAsyncSearchesListRequest{}, - proxyResp: &seqapi.GetAsyncSearchesListResponse{ + req: &seqapi.GetAsyncSearchesListRequest{}, + resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -86,8 +117,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(mockTime.Add(-1 * time.Hour)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-1 * time.Hour)), + To: timestamppb.New(someMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -101,9 +132,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(mockTime.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(300 * time.Second)), - CanceledAt: timestamppb.New(mockTime), + StartedAt: timestamppb.New(someMoment.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(300 * time.Second)), + CanceledAt: timestamppb.New(someMoment), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -113,49 +144,62 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - repoReq: types.GetAsyncSearchesListRequest{}, - repoResp: []types.AsyncSearchInfo{ + }, + }, + { + name: "ok_filters", + req: getAsyncSearchesListRequest{ + Status: &statusDone, + Limit: 10, + Offset: 20, + Owner: &mockUserName1, + }, + want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ + Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, + SearchId: mockSearchID, + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: "message:error", + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), + WithDocs: true, + Size: 100, + }, + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + Progress: 1, + DiskUsage: 512, OwnerName: mockUserName1, }, - { - SearchID: mockSearchID2, - OwnerID: mockProfileID2, - OwnerName: mockUserName2, - }, }, - searchIDs: []string{mockSearchID1, mockSearchID2}, - }, - wantRespBody: `{"searches":[{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","status":"done","request":{"retention":"seconds:60","query":"message:error","from":"2025-08-06T17:37:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","with_docs":true,"size":100},"started_at":"2025-08-06T17:51:42.000000123Z","expires_at":"2025-08-06T17:52:42.000000123Z","progress":1,"disk_usage":"512","owner_name":"some_user_1","error":"some error"},{"search_id":"9e4c068e-d4f4-4a5d-be27-a6524a70d70d","status":"canceled","request":{"retention":"seconds:360","query":"message:error and level:3","from":"2025-08-06T16:52:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","aggregations":[{"field":"x","group_by":"level","agg_func":"avg","interval":"30s"}],"histogram":{"interval":"1s"},"with_docs":false,"size":0},"started_at":"2025-08-06T17:51:12.000000123Z","expires_at":"2025-08-06T17:57:12.000000123Z","canceled_at":"2025-08-06T17:52:12.000000123Z","progress":1,"disk_usage":"256","owner_name":"some_user_2"}],"error":{"code":"ERROR_CODE_NO"}}`, - wantStatus: http.StatusOK, - }, - { - name: "ok_filters", - reqBody: `{"limit":10,"offset":20,"status":"done","owner_name":"some_user_1"}`, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_NO, + }, + }), mockArgs: &mockArgs{ - proxyReq: &seqapi.GetAsyncSearchesListRequest{ + req: &seqapi.GetAsyncSearchesListRequest{ Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE.Enum(), OwnerName: &mockUserName1, Limit: 10, Offset: 20, }, - proxyResp: &seqapi.GetAsyncSearchesListResponse{ + resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -165,41 +209,53 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - repoReq: types.GetAsyncSearchesListRequest{ - Owner: &mockUserName1, - }, - repoResp: []types.AsyncSearchInfo{ + }, + }, + { + name: "partial_response", + req: getAsyncSearchesListRequest{}, + want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ + Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, + SearchId: mockSearchID, + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: "message:error", + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), + WithDocs: true, + Size: 100, + }, + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + Progress: 1, + DiskUsage: 512, OwnerName: mockUserName1, }, }, - searchIDs: []string{mockSearchID1}, - }, - wantRespBody: `{"searches":[{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","status":"done","request":{"retention":"seconds:60","query":"message:error","from":"2025-08-06T17:37:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","with_docs":true,"size":100},"started_at":"2025-08-06T17:51:42.000000123Z","expires_at":"2025-08-06T17:52:42.000000123Z","progress":1,"disk_usage":"512","owner_name":"some_user_1"}],"error":{"code":"ERROR_CODE_NO"}}`, - wantStatus: http.StatusOK, - }, - { - name: "partial_response", - reqBody: `{}`, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_PARTIAL_RESPONSE, + Message: "partial response", + }, + }), mockArgs: &mockArgs{ - proxyReq: &seqapi.GetAsyncSearchesListRequest{}, - proxyResp: &seqapi.GetAsyncSearchesListResponse{ + req: &seqapi.GetAsyncSearchesListRequest{}, + resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -210,56 +266,69 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Message: "partial response", }, }, - repoReq: types.GetAsyncSearchesListRequest{}, - repoResp: []types.AsyncSearchInfo{ - { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, - }, - }, - searchIDs: []string{mockSearchID1}, }, - wantRespBody: `{"searches":[{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","status":"done","request":{"retention":"seconds:60","query":"message:error","from":"2025-08-06T17:37:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","with_docs":true,"size":100},"started_at":"2025-08-06T17:51:42.000000123Z","expires_at":"2025-08-06T17:52:42.000000123Z","progress":1,"disk_usage":"512","owner_name":"some_user_1"}],"error":{"code":"ERROR_CODE_PARTIAL_RESPONSE","message":"partial response"}}`, - wantStatus: http.StatusOK, - }, - { - name: "err_limit", - reqBody: `{"limit":-10,"offset":20}`, - wantRespBody: `{"message":"invalid request field: 'limit' must be non-negative"}`, - wantStatus: http.StatusBadRequest, }, { - name: "err_offset", - reqBody: `{"limit":10,"offset":-20}`, - wantRespBody: `{"message":"invalid request field: 'offset' must be non-negative"}`, - wantStatus: http.StatusBadRequest, + name: "err_limit", + req: getAsyncSearchesListRequest{ + Limit: -10, + Offset: 20, + }, + wantErr: true, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, + name: "err_offset", + req: getAsyncSearchesListRequest{ + Limit: 10, + Offset: -20, + }, + wantErr: true, }, { - name: "query_too_long", - reqBody: "{}", + name: "query_too_long", + req: getAsyncSearchesListRequest{}, + want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ + Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ + { + SearchId: mockSearchID, + Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, + Request: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: tooLongQuery, + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), + WithDocs: true, + Size: 100, + }, + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + Progress: 1, + DiskUsage: 512, + OwnerName: mockUserName1, + }, + }, + Error: &seqapi.Error{ + Code: seqapi.ErrorCode_ERROR_CODE_PARTIAL_RESPONSE, + Message: "partial response", + }, + }), mockArgs: &mockArgs{ - proxyReq: &seqapi.GetAsyncSearchesListRequest{}, - proxyResp: &seqapi.GetAsyncSearchesListResponse{ + req: &seqapi.GetAsyncSearchesListRequest{}, + resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID1, + SearchId: mockSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: tooLongQuery, - From: timestamppb.New(mockTime.Add(-15 * time.Minute)), - To: timestamppb.New(mockTime), + From: timestamppb.New(someMoment.Add(-15 * time.Minute)), + To: timestamppb.New(someMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(mockTime.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(mockTime.Add(30 * time.Second)), + StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -270,52 +339,36 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Message: "partial response", }, }, - repoReq: types.GetAsyncSearchesListRequest{}, - repoResp: []types.AsyncSearchInfo{ - { - SearchID: mockSearchID1, - OwnerID: mockProfileID1, - OwnerName: mockUserName1, - }, - }, - searchIDs: []string{mockSearchID1}, }, - wantRespBody: `{"searches":[{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656","status":"done","request":{"retention":"seconds:60","query":"` + TruncatedQuery + `...","from":"2025-08-06T17:37:12.000000123Z","to":"2025-08-06T17:52:12.000000123Z","with_docs":true,"size":100},"started_at":"2025-08-06T17:51:42.000000123Z","expires_at":"2025-08-06T17:52:42.000000123Z","progress":1,"disk_usage":"512","owner_name":"some_user_1"}],"error":{"code":"ERROR_CODE_PARTIAL_RESPONSE","message":"partial response"}}`, - wantStatus: http.StatusOK, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - seqData := test.APITestData{ - AsyncCfg: config.AsyncSearch{ - ListQueryLengthLimit: 1000, - }, - } + seqData := test.APITestData{} if tt.mockArgs != nil { ctrl := gomock.NewController(t) - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().GetAsyncSearchesList(gomock.Any(), tt.mockArgs.repoReq). - Return(tt.mockArgs.repoResp, tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock - - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetAsyncSearchesList(gomock.Any(), tt.mockArgs.proxyReq, tt.mockArgs.searchIDs). - Return(tt.mockArgs.proxyResp, tt.mockArgs.proxyErr).Times(1) - seqData.Mocks.SeqDB = seqDbMock + svcMock := mock_asyncsearches.NewMockService(ctrl) + svcMock.EXPECT(). + GetAsyncSearchesList(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/list", strings.NewReader(tt.reqBody)) + api := setupAPIWithAsyncSearches(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetAsyncSearchesList, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAsyncSearchesListRequest, getAsyncSearchesListResponse]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/list", + Req: tt.req, + Handler: api.serveGetAsyncSearchesList, + Want: tt.want, + WantErr: tt.wantErr, }) }) } @@ -323,13 +376,12 @@ func TestServeGetAsyncSearchesList(t *testing.T) { func TestServeGetAsyncSearchesList_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/list", strings.NewReader("{}")) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetAsyncSearchesList, - WantRespBody: `{"message":"async searches disabled"}`, - WantStatus: http.StatusBadRequest, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAsyncSearchesListRequest, struct{}]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/list", + Handler: api.serveGetAsyncSearchesList, + WantErr: true, }) } diff --git a/internal/api/seqapi/v1/http/get_envs_test.go b/internal/api/seqapi/v1/http/get_envs_test.go index e2f54a6..192f55d 100644 --- a/internal/api/seqapi/v1/http/get_envs_test.go +++ b/internal/api/seqapi/v1/http/get_envs_test.go @@ -1,22 +1,19 @@ package http import ( - "encoding/json" "net/http" - "net/http/httptest" "testing" - "github.com/stretchr/testify/require" - + "github.com/ozontech/seq-ui/internal/api/httputil" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/config" ) func TestServeGetEnvs(t *testing.T) { tests := []struct { - name string - cfg config.SeqAPI - wantEnvs []envInfo + name string + cfg config.SeqAPI + want getEnvsResponse }{ { name: "single_env", @@ -29,14 +26,16 @@ func TestServeGetEnvs(t *testing.T) { SeqCLIMaxSearchLimit: 10000, }, }, - wantEnvs: []envInfo{ - { - Env: "", - MaxSearchLimit: 100, - MaxExportLimit: 200, - MaxParallelExportRequests: 2, - MaxAggregationsPerRequest: 5, - SeqCliMaxSearchLimit: 10000, + want: getEnvsResponse{ + []envInfo{ + { + Env: "", + MaxSearchLimit: 100, + MaxExportLimit: 200, + MaxParallelExportRequests: 2, + MaxAggregationsPerRequest: 5, + SeqCliMaxSearchLimit: 10000, + }, }, }, }, @@ -98,53 +97,54 @@ func TestServeGetEnvs(t *testing.T) { }, DefaultEnv: "cluster-10", }, - wantEnvs: []envInfo{ - { - Env: "cluster-10", - MaxSearchLimit: 1000, - MaxExportLimit: 500, - MaxParallelExportRequests: 10, - MaxAggregationsPerRequest: 5, - SeqCliMaxSearchLimit: 2000, - }, - { - Env: "cluster-102", - MaxSearchLimit: 500, - MaxExportLimit: 250, - MaxParallelExportRequests: 5, - MaxAggregationsPerRequest: 3, - SeqCliMaxSearchLimit: 1000, - }, - { - Env: "cluster-220", - MaxSearchLimit: 1000, - MaxExportLimit: 500, - MaxParallelExportRequests: 10, - MaxAggregationsPerRequest: 5, - SeqCliMaxSearchLimit: 2000, - }, - { - Env: "prod", - MaxSearchLimit: 500, - MaxExportLimit: 250, - MaxParallelExportRequests: 5, - MaxAggregationsPerRequest: 3, - SeqCliMaxSearchLimit: 1000, - }, - { - Env: "wyanki", - MaxSearchLimit: 500, - MaxExportLimit: 250, - MaxParallelExportRequests: 5, - MaxAggregationsPerRequest: 3, - SeqCliMaxSearchLimit: 1000, + want: getEnvsResponse{ + []envInfo{ + { + Env: "cluster-10", + MaxSearchLimit: 1000, + MaxExportLimit: 500, + MaxParallelExportRequests: 10, + MaxAggregationsPerRequest: 5, + SeqCliMaxSearchLimit: 2000, + }, + { + Env: "cluster-102", + MaxSearchLimit: 500, + MaxExportLimit: 250, + MaxParallelExportRequests: 5, + MaxAggregationsPerRequest: 3, + SeqCliMaxSearchLimit: 1000, + }, + { + Env: "cluster-220", + MaxSearchLimit: 1000, + MaxExportLimit: 500, + MaxParallelExportRequests: 10, + MaxAggregationsPerRequest: 5, + SeqCliMaxSearchLimit: 2000, + }, + { + Env: "prod", + MaxSearchLimit: 500, + MaxExportLimit: 250, + MaxParallelExportRequests: 5, + MaxAggregationsPerRequest: 3, + SeqCliMaxSearchLimit: 1000, + }, + { + Env: "wyanki", + MaxSearchLimit: 500, + MaxExportLimit: 250, + MaxParallelExportRequests: 5, + MaxAggregationsPerRequest: 3, + SeqCliMaxSearchLimit: 1000, + }, }, }, }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -152,16 +152,14 @@ func TestServeGetEnvs(t *testing.T) { Cfg: tt.cfg, } - api := initTestAPI(seqData) - - req := httptest.NewRequest(http.MethodGet, "/seqapi/v1/envs", http.NoBody) - w := httptest.NewRecorder() - api.serveGetEnvs(w, req) + api := setupAPI(seqData) - var response getEnvsResponse - err := json.NewDecoder(w.Body).Decode(&response) - require.NoError(t, err, "failed to decode response") - require.ElementsMatch(t, tt.wantEnvs, response.Envs, "Returned envs do not match expected") + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getEnvsResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/envs", + Handler: api.serveGetEnvs, + Want: tt.want, + }) }) } } diff --git a/internal/api/seqapi/v1/http/histogram_test.go b/internal/api/seqapi/v1/http/histogram_test.go index ea5be57..ca14fa1 100644 --- a/internal/api/seqapi/v1/http/histogram_test.go +++ b/internal/api/seqapi/v1/http/histogram_test.go @@ -2,12 +2,8 @@ package http import ( "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" - "time" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -19,15 +15,6 @@ import ( ) func TestServeGetHistogram(t *testing.T) { - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(time.Second) - - formatReqBody := func(interval string) string { - return fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"interval":%q}`, - query, from.Format(time.RFC3339), to.Format(time.RFC3339), interval) - } - type mockArgs struct { req *seqapi.GetHistogramRequest resp *seqapi.GetHistogramResponse @@ -37,15 +24,30 @@ func TestServeGetHistogram(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req getHistogramRequest + want getHistogramResponse + wantErr bool mockArgs *mockArgs }{ { - name: "ok", - reqBody: formatReqBody("5s"), + name: "ok", + req: getHistogramRequest{ + Query: query, + From: from, + To: to, + Interval: "5s", + }, + want: getHistogramResponse{ + Histogram: histogram{ + Buckets: histogramBuckets{ + {Key: "0", DocCount: "1"}, + {Key: "100", DocCount: "2"}, + }, + }, + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ Query: query, @@ -60,12 +62,22 @@ func TestServeGetHistogram(t *testing.T) { }, }, }, - wantRespBody: `{"histogram":{"buckets":[{"key":"0","docCount":"1"},{"key":"100","docCount":"2"}]},"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, }, { - name: "err_partial_response", - reqBody: formatReqBody("10s"), + name: "err_partial_response", + req: getHistogramRequest{ + Query: query, + From: from, + To: to, + Interval: "10s", + }, + want: getHistogramResponse{ + Histogram: histogram{ + Buckets: histogramBuckets{}, + }, + Error: apiError{Code: aecPartialResponse, Message: "partial response"}, + PartialResponse: true, + }, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ Query: query, @@ -81,17 +93,16 @@ func TestServeGetHistogram(t *testing.T) { PartialResponse: true, }, }, - wantRespBody: `{"histogram":{"buckets":[]},"error":{"code":"ERROR_CODE_PARTIAL_RESPONSE","message":"partial response"},"partialResponse":true}`, - wantStatus: http.StatusOK, - }, - { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, }, { - name: "err_client", - reqBody: formatReqBody("20s"), + name: "err_client", + req: getHistogramRequest{ + Query: query, + From: from, + To: to, + Interval: "20s", + }, + wantErr: true, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ Query: query, @@ -101,11 +112,10 @@ func TestServeGetHistogram(t *testing.T) { }, err: errors.New("client error"), }, - wantStatus: http.StatusInternalServerError, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -113,22 +123,25 @@ func TestServeGetHistogram(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().GetHistogram(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) + + seqDbMock.EXPECT(). + GetHistogram(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) seqData.Mocks.SeqDB = seqDbMock } - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/histogram", strings.NewReader(tt.reqBody)) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetHistogram, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getHistogramRequest, getHistogramResponse]{ + Method: http.MethodPost, + Target: "/seqapi/v1/histogram", + Req: tt.req, + Handler: api.serveGetHistogram, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/seqapi/v1/http/limits_test.go b/internal/api/seqapi/v1/http/limits_test.go index 28d3748..afb1e87 100644 --- a/internal/api/seqapi/v1/http/limits_test.go +++ b/internal/api/seqapi/v1/http/limits_test.go @@ -2,7 +2,6 @@ package http import ( "net/http" - "net/http/httptest" "testing" "github.com/ozontech/seq-ui/internal/api/httputil" @@ -12,10 +11,11 @@ import ( func TestServeGetLimits(t *testing.T) { tests := []struct { - name string - env string - cfg config.SeqAPI - wantRespBody string + name string + + env string + cfg config.SeqAPI + want getLimitsResponse }{ { name: "ok", @@ -29,16 +29,22 @@ func TestServeGetLimits(t *testing.T) { SeqCLIMaxSearchLimit: 10000, }, }, - wantRespBody: `{"maxSearchLimit":100,"maxExportLimit":200,"maxParallelExportRequests":2,"maxAggregationsPerRequest":5,"seqCliMaxSearchLimit":10000}`, + want: getLimitsResponse{ + MaxSearchLimit: 100, + MaxExportLimit: 200, + MaxParallelExportRequests: 2, + MaxAggregationsPerRequest: 5, + SeqCliMaxSearchLimit: 10000, + }, }, { - name: "empty", - env: "default", - wantRespBody: `{"maxSearchLimit":0,"maxExportLimit":0,"maxParallelExportRequests":0,"maxAggregationsPerRequest":0,"seqCliMaxSearchLimit":0}`, + name: "empty", + env: "default", + want: getLimitsResponse{}, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -46,14 +52,13 @@ func TestServeGetLimits(t *testing.T) { Cfg: tt.cfg, } - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodGet, "/seqapi/v1/limits", http.NoBody) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetLimits, - WantRespBody: tt.wantRespBody, - WantStatus: http.StatusOK, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getLimitsResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/limits", + Handler: api.serveGetLimits, + Want: tt.want, }) }) } diff --git a/internal/api/seqapi/v1/http/logs_lifespan_test.go b/internal/api/seqapi/v1/http/logs_lifespan_test.go index a3d4401..fcce6c6 100644 --- a/internal/api/seqapi/v1/http/logs_lifespan_test.go +++ b/internal/api/seqapi/v1/http/logs_lifespan_test.go @@ -1,9 +1,7 @@ package http import ( - "errors" "net/http" - "net/http/httptest" "strconv" "testing" "time" @@ -22,22 +20,11 @@ import ( ) func TestServeGetLogsLifespan(t *testing.T) { - const ( - cacheKey = "logs_lifespan" - cacheTTL = 1 * time.Minute - - result = 10 * time.Hour - resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) - resultRespBody = `{"lifespan":36000}` - ) - unparsable := func(s string) bool { _, err := strconv.Atoi(s) return err != nil } - oldestStorageTime := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC) - tests := []struct { name string @@ -47,16 +34,15 @@ func TestServeGetLogsLifespan(t *testing.T) { clientResp *seqapi.StatusResponse clientErr error - wantStatus int - wantRespBody string + wantErr bool + want getLogsLifespanResponse }{ { name: "ok_cached", getOp: test.CacheMockArgs{ Value: resultStr, }, - wantStatus: http.StatusOK, - wantRespBody: resultRespBody, + want: getLogsLifespanResponse{Lifespan: 36000}, }, { name: "ok_cached_unparsable", @@ -67,10 +53,9 @@ func TestServeGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(oldestStorageTime), + OldestStorageTime: timestamppb.New(someMoment), }, - wantStatus: http.StatusOK, - wantRespBody: resultRespBody, + want: getLogsLifespanResponse{Lifespan: 36000}, }, { name: "ok_no_cached", @@ -81,18 +66,17 @@ func TestServeGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(oldestStorageTime), + OldestStorageTime: timestamppb.New(someMoment), }, - wantStatus: http.StatusOK, - wantRespBody: resultRespBody, + want: getLogsLifespanResponse{Lifespan: 36000}, }, { name: "err_client", getOp: test.CacheMockArgs{ Err: cache.ErrNotFound, }, - clientErr: errors.New("network error"), - wantStatus: http.StatusInternalServerError, + clientErr: errSomethingWrong, + wantErr: true, }, { name: "err_nil_oldest_storage_time", @@ -102,11 +86,11 @@ func TestServeGetLogsLifespan(t *testing.T) { clientResp: &seqapi.StatusResponse{ OldestStorageTime: nil, }, - wantStatus: http.StatusInternalServerError, + wantErr: true, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -118,37 +102,43 @@ func TestServeGetLogsLifespan(t *testing.T) { }, }, } - ctrl := gomock.NewController(t) + ctrl := gomock.NewController(t) cacheMock := mock_cache.NewMockCache(ctrl) - cacheMock.EXPECT().Get(gomock.Any(), cacheKey). - Return(tt.getOp.Value, tt.getOp.Err).Times(1) + + cacheMock.EXPECT(). + Get(gomock.Any(), cacheKey). + Return(tt.getOp.Value, tt.getOp.Err). + Times(1) seqData.Mocks.Cache = cacheMock if tt.getOp.Err != nil || unparsable(tt.getOp.Value) { seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().Status(gomock.Any(), gomock.Any()). - Return(proto.Clone(tt.clientResp), tt.clientErr).Times(1) + seqDbMock.EXPECT(). + Status(gomock.Any(), gomock.Any()). + Return(proto.Clone(tt.clientResp), tt.clientErr). + Times(1) seqData.Mocks.SeqDB = seqDbMock if tt.clientErr == nil && tt.clientResp.OldestStorageTime != nil { - cacheMock.EXPECT().SetWithTTL(gomock.Any(), cacheKey, tt.setOp.Value, cacheTTL). - Return(tt.setOp.Err).Times(1) + cacheMock.EXPECT(). + SetWithTTL(gomock.Any(), cacheKey, tt.setOp.Value, cacheTTL). + Return(tt.setOp.Err). + Times(1) } } - api := initTestAPI(seqData) + api := setupAPI(seqData) api.nowFn = func() time.Time { - return oldestStorageTime.Add(result) + return someMoment.Add(result) } - req := httptest.NewRequest(http.MethodGet, "/seqapi/v1/logs_lifespan", http.NoBody) - - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetLogsLifespan, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getLogsLifespanResponse]{ + Method: http.MethodGet, + Target: "/seqapi/v1/logs_lifespan", + Handler: api.serveGetLogsLifespan, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/seqapi/v1/http/search_test.go b/internal/api/seqapi/v1/http/search_test.go index 1dc3932..5defcaf 100644 --- a/internal/api/seqapi/v1/http/search_test.go +++ b/internal/api/seqapi/v1/http/search_test.go @@ -1,16 +1,9 @@ package http import ( - "encoding/json" - "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" - "time" - "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -23,35 +16,6 @@ import ( ) func TestServeSearch(t *testing.T) { - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(time.Second) - eventTime := from.Add(time.Millisecond) // 2023-09-25T10:20:30.001Z - - formatReqBody := func(limit, offset int, withTotal bool, histInterval string, aggQueries aggregationQueries, order string) string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"limit":%d,"offset":%d`, - query, from.Format(time.RFC3339), to.Format(time.RFC3339), limit, offset)) - - if withTotal { - sb.WriteString(fmt.Sprintf(`,"withTotal":%v`, withTotal)) - } - if histInterval != "" { - sb.WriteString(fmt.Sprintf(`,"histogram":{"interval":%q}`, histInterval)) - } - if len(aggQueries) > 0 { - aggQueriesRaw, err := json.Marshal(aggQueries) - assert.NoError(t, err) - sb.WriteString(fmt.Sprintf(`,"aggregations":%s`, aggQueriesRaw)) - } - if order != "" { - sb.WriteString(fmt.Sprintf(`,"order":%q`, order)) - } - - sb.WriteString("}") - return sb.String() - } - type mockArgs struct { req *seqapi.SearchRequest resp *seqapi.SearchResponse @@ -61,16 +25,31 @@ func TestServeSearch(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req searchRequest + want searchResponse + cfg config.SeqAPI + wantErr bool mockArgs *mockArgs - cfg config.SeqAPI }{ { - name: "ok_simple", - reqBody: formatReqBody(3, 0, false, "", nil, ""), + name: "ok_simple", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(3, eventTime)), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, + cfg: test.SetCfgDefaults(config.SeqAPI{ + SeqAPIOptions: &config.SeqAPIOptions{ + MaxSearchLimit: 5, + }, + }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -86,17 +65,27 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: `{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test2","data":{"field1":"val1","field2":"val2"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test3","data":{"field1":"val1","field2":"val2","field3":"val3"},"time":"2023-09-25T10:20:30.001Z"}],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + }, + { + name: "ok_with_total", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + WithTotal: true, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(3, eventTime)), + Total: "10", + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }), - }, - { - name: "ok_with_total", - reqBody: formatReqBody(3, 0, true, "", nil, ""), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -114,17 +103,26 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: `{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test2","data":{"field1":"val1","field2":"val2"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test3","data":{"field1":"val1","field2":"val2","field3":"val3"},"time":"2023-09-25T10:20:30.001Z"}],"total":"10","error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + }, + { + name: "ok_order_asc", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + Order: oASC, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(3, eventTime)), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }), - }, - { - name: "ok_order_asc", - reqBody: formatReqBody(3, 0, false, "", nil, string(oASC)), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -141,17 +139,29 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: `{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test2","data":{"field1":"val1","field2":"val2"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test3","data":{"field1":"val1","field2":"val2","field3":"val3"},"time":"2023-09-25T10:20:30.001Z"}],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + }, + { + name: "ok_with_hist", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + Histogram: struct { + Interval string "json:\"interval\"" + }{Interval: "5s"}, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(3, eventTime)), + Histogram: histogramFromProto(test.MakeHistogram(2), false), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }), - }, - { - name: "ok_with_hist", - reqBody: formatReqBody(3, 0, false, "5s", nil, ""), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -171,23 +181,35 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: `{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test2","data":{"field1":"val1","field2":"val2"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test3","data":{"field1":"val1","field2":"val2","field3":"val3"},"time":"2023-09-25T10:20:30.001Z"}],"histogram":{"buckets":[{"key":"0","docCount":"1"},{"key":"100","docCount":"2"}]},"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + }, + { + name: "ok_with_aggs", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + Aggregations: aggregationQueries{ + { + Field: "test1", + GroupBy: "service", + Func: afAvg, + }, + }, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(3, eventTime)), + Aggregations: aggregationsFromProto(test.MakeAggregations(2, 3, &test.MakeAggOpts{ + NotExists: 5, + }), false), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }), - }, - { - name: "ok_with_aggs", - reqBody: formatReqBody(3, 0, false, "", aggregationQueries{ - { - Field: "test1", - GroupBy: "service", - Func: afAvg, - }, - }, ""), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -213,17 +235,25 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: `{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test2","data":{"field1":"val1","field2":"val2"},"time":"2023-09-25T10:20:30.001Z"},{"id":"test3","data":{"field1":"val1","field2":"val2","field3":"val3"},"time":"2023-09-25T10:20:30.001Z"}],"aggregations":[{"buckets":[{"key":"test1","value":1,"not_exists":5},{"key":"test2","value":2,"not_exists":5},{"key":"test3","value":3,"not_exists":5}]},{"buckets":[{"key":"test1","value":1,"not_exists":5},{"key":"test2","value":2,"not_exists":5},{"key":"test3","value":3,"not_exists":5}]}],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + }, + { + name: "ok_empty_events", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(0, eventTime)), + Error: apiError{Code: aecNo}, + PartialResponse: false, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }), - }, - { - name: "ok_empty_events", - reqBody: formatReqBody(3, 0, false, "", nil, ""), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -239,17 +269,25 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: `{"events":[],"error":{"code":"ERROR_CODE_NO"},"partialResponse":false}`, - wantStatus: http.StatusOK, + }, + { + name: "err_partial_response", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(1, eventTime)), + Error: apiError{Code: aecPartialResponse, Message: "partial response"}, + PartialResponse: true, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }), - }, - { - name: "err_partial_response", - reqBody: formatReqBody(3, 0, false, "", nil, ""), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -267,58 +305,87 @@ func TestServeSearch(t *testing.T) { PartialResponse: true, }, }, - wantRespBody: `{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"}],"error":{"code":"ERROR_CODE_PARTIAL_RESPONSE","message":"partial response"},"partialResponse":true}`, - wantStatus: http.StatusOK, - cfg: test.SetCfgDefaults(config.SeqAPI{ - SeqAPIOptions: &config.SeqAPIOptions{ - MaxSearchLimit: 5, - }, - }), }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - }, - { - name: "err_search_limit_zero", - reqBody: formatReqBody(0, 0, false, "", nil, ""), - wantStatus: http.StatusBadRequest, + name: "err_search_limit_zero", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 0, + }, + wantErr: true, }, { - name: "err_search_limit_max", - reqBody: formatReqBody(10, 0, false, "", nil, ""), - wantStatus: http.StatusBadRequest, + name: "err_search_limit_max", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 10, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, }, }, + wantErr: true, }, { - name: "err_aggs_limit_max", - reqBody: formatReqBody(3, 0, false, "", aggregationQueries{{}, {}, {}}, ""), - wantStatus: http.StatusBadRequest, + name: "err_aggs_limit_max", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + Aggregations: aggregationQueries{{}, {}, {}}, + }, cfg: config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, MaxAggregationsPerRequest: 2, }, }, - }, { - name: "err_offset_too_high", - reqBody: formatReqBody(3, 11, false, "", nil, ""), - wantStatus: http.StatusBadRequest, + wantErr: true, + }, + { + name: "err_offset_too_high", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + Offset: 11, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ MaxSearchLimit: 5, MaxSearchOffsetLimit: 10, }, }), + wantErr: true, }, { - name: "err_total_too_high", - reqBody: formatReqBody(3, 0, true, "", nil, ""), + name: "err_total_too_high", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + WithTotal: true, + }, + want: searchResponse{ + Events: eventsFromProto(test.MakeEvents(1, eventTime)), + Total: "11", + Error: apiError{Code: aecQueryTooHeavy, Message: api_error.ErrQueryTooHeavy.Error()}, + PartialResponse: false, + }, + cfg: test.SetCfgDefaults(config.SeqAPI{ + SeqAPIOptions: &config.SeqAPIOptions{ + MaxSearchLimit: 5, + MaxSearchOffsetLimit: 10, + }, + }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -337,18 +404,21 @@ func TestServeSearch(t *testing.T) { }, }, }, - wantRespBody: fmt.Sprintf(`{"events":[{"id":"test1","data":{"field1":"val1"},"time":"2023-09-25T10:20:30.001Z"}],"total":"11","error":{"code":"ERROR_CODE_QUERY_TOO_HEAVY","message":%q},"partialResponse":false}`, api_error.ErrQueryTooHeavy.Error()), - wantStatus: http.StatusOK, + }, + { + name: "err_client", + req: searchRequest{ + Query: query, + From: from, + To: to, + Limit: 3, + }, cfg: test.SetCfgDefaults(config.SeqAPI{ SeqAPIOptions: &config.SeqAPIOptions{ - MaxSearchLimit: 5, - MaxSearchOffsetLimit: 10, + MaxSearchLimit: 5, }, }), - }, - { - name: "err_client", - reqBody: formatReqBody(3, 0, false, "", nil, ""), + wantErr: true, mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: query, @@ -357,18 +427,12 @@ func TestServeSearch(t *testing.T) { Limit: 3, Offset: 0, }, - err: errors.New("client error"), + err: errSomethingWrong, }, - wantStatus: http.StatusInternalServerError, - cfg: test.SetCfgDefaults(config.SeqAPI{ - SeqAPIOptions: &config.SeqAPIOptions{ - MaxSearchLimit: 5, - }, - }), }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -380,20 +444,23 @@ func TestServeSearch(t *testing.T) { ctrl := gomock.NewController(t) seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().Search(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) + seqDbMock.EXPECT(). + Search(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) seqData.Mocks.SeqDB = seqDbMock } - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/search", strings.NewReader(tt.reqBody)) + api := setupAPI(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveSearch, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[searchRequest, searchResponse]{ + Method: http.MethodPost, + Target: "/seqapi/v1/search", + Req: tt.req, + Handler: api.serveSearch, + Want: tt.want, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/seqapi/v1/http/start_async_search.go b/internal/api/seqapi/v1/http/start_async_search.go index 0904cc1..1096ec8 100644 --- a/internal/api/seqapi/v1/http/start_async_search.go +++ b/internal/api/seqapi/v1/http/start_async_search.go @@ -103,13 +103,7 @@ func (a *API) serveStartAsyncSearch(w http.ResponseWriter, r *http.Request) { span.SetAttributes(spanAttributes...) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - - resp, err := a.asyncSearches.StartAsyncSearch(ctx, profileID, httpReq.toProto(parsedRetention)) + resp, err := a.asyncSearches.StartAsyncSearch(ctx, httpReq.toProto(parsedRetention)) if err != nil { wr.Error(err, http.StatusInternalServerError) return diff --git a/internal/api/seqapi/v1/http/start_async_search_test.go b/internal/api/seqapi/v1/http/start_async_search_test.go index d1ac82d..f0bdde5 100644 --- a/internal/api/seqapi/v1/http/start_async_search_test.go +++ b/internal/api/seqapi/v1/http/start_async_search_test.go @@ -1,11 +1,7 @@ package http import ( - "context" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" "time" @@ -15,56 +11,56 @@ import ( "github.com/ozontech/seq-ui/internal/api/httputil" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" - "github.com/ozontech/seq-ui/internal/app/types" - mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) func TestServeStartAsyncSearch(t *testing.T) { - const ( - mockSearchID = "c9a34cf8-4c66-484e-9cc2-42979d848656" - mockUserName = "some_user" - mockProfileID = 1 - meta = `{"some":"meta"}` - ) - - query := "message:error" - from := time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to := from.Add(time.Second) - - formatReqBody := func(retention string) string { - return fmt.Sprintf(`{"retention":%q,"query":%q,"from":%q,"to":%q,"with_docs":true,"size":100,"meta":"{\"some\":\"meta\"}","histogram":{"interval":"1s"},"aggregations":[{"field":"v","group_by":"level","agg_func":"avg","quantiles":[0.95],"interval":"30s"}]}`, - retention, query, from.Format(time.RFC3339), to.Format(time.RFC3339)) - } - type mockArgs struct { - proxyReq *seqapi.StartAsyncSearchRequest - proxyResp *seqapi.StartAsyncSearchResponse - proxyErr error - - profilesReq types.GetOrCreateUserProfileRequest - profilesResp types.UserProfile - profilesErr error - - repoReq types.SaveAsyncSearchRequest - repoErr error + req *seqapi.StartAsyncSearchRequest + resp *seqapi.StartAsyncSearchResponse + err error } tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req startAsyncSearchRequest + want startAsyncSearchResponse + wantErr bool mockArgs *mockArgs }{ { - name: "ok", - reqBody: formatReqBody("60s"), + name: "ok", + req: startAsyncSearchRequest{ + Retention: "60s", + Query: query, + From: from, + To: to, + WithDocs: true, + Size: 100, + Meta: meta, + Histogram: &AsyncSearchRequestHistogram{ + Interval: "1s", + }, + Aggregations: aggregationTsQueries{ + { + aggregationQuery: aggregationQuery{ + Field: "v", + GroupBy: "level", + Func: afAvg, + Quantiles: []float64{0.95}, + }, + Interval: "30s", + }, + }, + }, + want: startAsyncSearchResponse{ + SearchID: mockSearchID, + }, mockArgs: &mockArgs{ - proxyReq: &seqapi.StartAsyncSearchRequest{ + req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: query, From: timestamppb.New(from), @@ -85,31 +81,64 @@ func TestServeStartAsyncSearch(t *testing.T) { }, Meta: meta, }, - proxyResp: &seqapi.StartAsyncSearchResponse{ + resp: &seqapi.StartAsyncSearchResponse{ SearchId: mockSearchID, }, - profilesReq: types.GetOrCreateUserProfileRequest{ - UserName: mockUserName, + }, + }, + { + name: "err_svc", + req: startAsyncSearchRequest{ + Retention: "60s", + Query: query, + From: from, + To: to, + WithDocs: true, + Size: 100, + Meta: meta, + Histogram: &AsyncSearchRequestHistogram{ + Interval: "1s", }, - profilesResp: types.UserProfile{ - ID: mockProfileID, - UserName: mockUserName, + Aggregations: aggregationTsQueries{ + { + aggregationQuery: aggregationQuery{ + Field: "v", + GroupBy: "level", + Func: afAvg, + Quantiles: []float64{0.95}, + }, + Interval: "30s", + }, }, - repoReq: types.SaveAsyncSearchRequest{ - SearchID: mockSearchID, - OwnerID: mockProfileID, - Meta: meta, + }, + wantErr: true, + mockArgs: &mockArgs{ + req: &seqapi.StartAsyncSearchRequest{ + Retention: durationpb.New(60 * time.Second), + Query: query, + From: timestamppb.New(from), + To: timestamppb.New(to), + WithDocs: true, + Size: 100, + Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ + Interval: "1s", + }, + Aggs: []*seqapi.AggregationQuery{ + { + Field: "v", + GroupBy: "level", + Func: seqapi.AggFunc_AGG_FUNC_AVG, + Quantiles: []float64{0.95}, + Interval: pointerTo("30s"), + }, + }, + Meta: meta, }, + err: errSomethingWrong, }, - wantRespBody: `{"search_id":"c9a34cf8-4c66-484e-9cc2-42979d848656"}`, - wantStatus: http.StatusOK, - }, - { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -118,32 +147,25 @@ func TestServeStartAsyncSearch(t *testing.T) { if tt.mockArgs != nil { ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) - seqDbMock := mock_seqdb.NewMockClient(ctrl) - seqDbMock.EXPECT().StartAsyncSearch(gomock.Any(), tt.mockArgs.proxyReq). - Return(tt.mockArgs.proxyResp, tt.mockArgs.proxyErr).Times(1) - seqData.Mocks.SeqDB = seqDbMock + svcMock.EXPECT(). + StartAsyncSearch(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) - profilesRepoMock := mock_repo.NewMockUserProfiles(ctrl) - profilesRepoMock.EXPECT().GetOrCreate(gomock.Any(), tt.mockArgs.profilesReq). - Return(tt.mockArgs.profilesResp, tt.mockArgs.profilesErr).Times(1) - seqData.Mocks.ProfilesRepo = profilesRepoMock - - asyncSearchesRepoMock := mock_repo.NewMockAsyncSearches(ctrl) - asyncSearchesRepoMock.EXPECT().SaveAsyncSearch(gomock.Any(), gomock.Any()). - Return(tt.mockArgs.repoErr).Times(1) - seqData.Mocks.AsyncSearchesRepo = asyncSearchesRepoMock + seqData.Mocks.AsyncSearchesSvc = svcMock } - api := initTestAPIWithAsyncSearches(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/start", strings.NewReader(tt.reqBody)) - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, mockUserName)) + api := setupAPIWithAsyncSearches(seqData) - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveStartAsyncSearch, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[startAsyncSearchRequest, startAsyncSearchResponse]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/start", + Req: tt.req, + Handler: api.serveStartAsyncSearch, + Want: tt.want, + WantErr: tt.wantErr, }) }) } @@ -151,13 +173,12 @@ func TestServeStartAsyncSearch(t *testing.T) { func TestServeStartAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := initTestAPI(seqData) - req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/start", strings.NewReader("{}")) - - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveStartAsyncSearch, - WantRespBody: `{"message":"async searches disabled"}`, - WantStatus: http.StatusBadRequest, + api := setupAPI(seqData) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[startAsyncSearchRequest, struct{}]{ + Method: http.MethodPost, + Target: "/seqapi/v1/async_search/start", + Handler: api.serveStartAsyncSearch, + WantErr: true, }) } diff --git a/internal/api/seqapi/v1/http/test_data.go b/internal/api/seqapi/v1/http/test_data.go index 455b472..e5ccbac 100644 --- a/internal/api/seqapi/v1/http/test_data.go +++ b/internal/api/seqapi/v1/http/test_data.go @@ -2,17 +2,45 @@ package http import ( "context" + "errors" + "net/http" + "strings" + "time" + + "github.com/go-chi/chi/v5" - "github.com/ozontech/seq-ui/internal/api/profiles" "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/config" "github.com/ozontech/seq-ui/internal/pkg/client/seqdb" - "github.com/ozontech/seq-ui/internal/pkg/repository" - "github.com/ozontech/seq-ui/internal/pkg/service" - asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches" ) -func initTestAPI(data test.APITestData) *API { +var ( + errSomethingWrong = errors.New("something happened wrong") + errCache = errors.New("test error") + tooLongQuery = strings.Repeat("message:error and level:3", 41) + errorMsg = "some error" + query = "message:error" + id1 = "test1" + id2 = "test2" + id3 = "test3" + id4 = "test4" + mockSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" + mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" + mockUserName1 = "some_user_1" + mockUserName2 = "some_user_2" + meta = `{"some":"meta"}` + resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) + cacheKey = "logs_lifespan" + from = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) + eventTime = from.Add(time.Millisecond) + someMoment = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) + to = from.Add(time.Second) + cacheTTL = time.Minute + ttl = 5 * time.Millisecond + result = 10 * time.Hour +) + +func setupAPI(data test.APITestData) *API { // when test cases don't explicitly provide configuration. if data.Cfg.SeqAPIOptions == nil { data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} @@ -24,20 +52,34 @@ func initTestAPI(data test.APITestData) *API { seqDBClients[envConfig.SeqDB] = data.Mocks.SeqDB } - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, nil, nil) + return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, nil) } -func initTestAPIWithAsyncSearches(data test.APITestData) *API { +func setupAPIWithAsyncSearches(data test.APITestData) *API { if data.Cfg.SeqAPIOptions == nil { data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} } seqDBClients := map[string]seqdb.Client{ config.DefaultSeqDBClientID: data.Mocks.SeqDB, } - as := asyncsearches.New(context.Background(), data.Mocks.AsyncSearchesRepo, data.Mocks.SeqDB, data.AsyncCfg) - s := service.New(&repository.Repository{ - UserProfiles: data.Mocks.ProfilesRepo, - }) - p := profiles.New(s) - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, as, p) + + return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, data.Mocks.AsyncSearchesSvc) +} + +func withAsyncSearchID(h http.HandlerFunc, id string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + rCtx := chi.NewRouteContext() + rCtx.URLParams.Add("id", id) + r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rCtx)) + h(w, r) + } +} + +func withEventID(h http.HandlerFunc, id string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + rCtx := chi.NewRouteContext() + rCtx.URLParams.Add("id", id) + r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rCtx)) + h(w, r) + } } diff --git a/internal/api/seqapi/v1/seqapi.go b/internal/api/seqapi/v1/seqapi.go index 9cdae47..f1a08c4 100644 --- a/internal/api/seqapi/v1/seqapi.go +++ b/internal/api/seqapi/v1/seqapi.go @@ -3,7 +3,6 @@ package seqapi_v1 import ( "github.com/go-chi/chi/v5" - "github.com/ozontech/seq-ui/internal/api/profiles" grpc_api "github.com/ozontech/seq-ui/internal/api/seqapi/v1/grpc" http_api "github.com/ozontech/seq-ui/internal/api/seqapi/v1/http" "github.com/ozontech/seq-ui/internal/app/config" @@ -22,12 +21,11 @@ func New( seqDB map[string]seqdb.Client, inmemWithRedisCache cache.Cache, redisCache cache.Cache, - asyncSearches *asyncsearches.Service, - p *profiles.Profiles, + asyncSearches asyncsearches.Service, ) *SeqAPI { return &SeqAPI{ - grpcAPI: grpc_api.New(cfg, seqDB, inmemWithRedisCache, redisCache, asyncSearches, p), - httpAPI: http_api.New(cfg, seqDB, inmemWithRedisCache, redisCache, asyncSearches, p), + grpcAPI: grpc_api.New(cfg, seqDB, inmemWithRedisCache, redisCache, asyncSearches), + httpAPI: http_api.New(cfg, seqDB, inmemWithRedisCache, redisCache, asyncSearches), } } diff --git a/internal/api/seqapi/v1/test/data.go b/internal/api/seqapi/v1/test/data.go index 46ea63d..0ab1d44 100644 --- a/internal/api/seqapi/v1/test/data.go +++ b/internal/api/seqapi/v1/test/data.go @@ -9,7 +9,7 @@ import ( "github.com/ozontech/seq-ui/internal/app/config" mock_cache "github.com/ozontech/seq-ui/internal/pkg/cache/mock" mock_seqdb "github.com/ozontech/seq-ui/internal/pkg/client/seqdb/mock" - mock_repo "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + mock_asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches/mock" "github.com/ozontech/seq-ui/pkg/seqapi/v1" ) @@ -20,16 +20,14 @@ type CacheMockArgs struct { } type Mocks struct { - SeqDB *mock_seqdb.MockClient - Cache *mock_cache.MockCache - AsyncSearchesRepo *mock_repo.MockAsyncSearches - ProfilesRepo *mock_repo.MockUserProfiles + SeqDB *mock_seqdb.MockClient + Cache *mock_cache.MockCache + AsyncSearchesSvc *mock_asyncsearches.MockService } type APITestData struct { - Cfg config.SeqAPI - AsyncCfg config.AsyncSearch - Mocks Mocks + Cfg config.SeqAPI + Mocks Mocks } func MakeEvent(id string, countData int, t time.Time) *seqapi.Event { diff --git a/internal/api/userprofile/v1/grpc/api.go b/internal/api/userprofile/v1/grpc/api.go index 202863d..05e765b 100644 --- a/internal/api/userprofile/v1/grpc/api.go +++ b/internal/api/userprofile/v1/grpc/api.go @@ -1,21 +1,18 @@ package grpc import ( - "github.com/ozontech/seq-ui/internal/api/profiles" - "github.com/ozontech/seq-ui/internal/pkg/service" + userprofilesservice "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" "github.com/ozontech/seq-ui/pkg/userprofile/v1" ) type API struct { userprofile.UnimplementedUserProfileServiceServer - service service.Service - profiles *profiles.Profiles + service userprofilesservice.Service } -func New(svc service.Service, p *profiles.Profiles) *API { +func New(svc userprofilesservice.Service) *API { return &API{ - service: svc, - profiles: p, + service: svc, } } diff --git a/internal/api/userprofile/v1/grpc/favorite_queries.go b/internal/api/userprofile/v1/grpc/favorite_queries.go index 55a1f43..32b2631 100644 --- a/internal/api/userprofile/v1/grpc/favorite_queries.go +++ b/internal/api/userprofile/v1/grpc/favorite_queries.go @@ -16,14 +16,8 @@ func (a *API) GetFavoriteQueries(ctx context.Context, _ *userprofile.GetFavorite ctx, span := tracing.StartSpan(ctx, "userprofile_v1_get_favorite_queries") defer span.End() - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } + request := types.GetFavoriteQueriesRequest{} - request := types.GetFavoriteQueriesRequest{ - ProfileID: profileID, - } favoriteQueries, err := a.service.GetFavoriteQueries(ctx, request) if err != nil { return nil, grpcutil.ProcessError(err) @@ -54,21 +48,15 @@ func (a *API) CreateFavoriteQuery(ctx context.Context, req *userprofile.CreateFa }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } + request := types.GetOrCreateFavoriteQueryRequest{Query: req.Query} - request := types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, - Query: req.Query, - } if req.RelativeFrom != nil { request.RelativeFrom = *req.RelativeFrom } if req.Name != nil { request.Name = *req.Name } + fqID, err := a.service.GetOrCreateFavoriteQuery(ctx, request) if err != nil { return nil, grpcutil.ProcessError(err) @@ -89,16 +77,9 @@ func (a *API) DeleteFavoriteQuery(ctx context.Context, req *userprofile.DeleteFa Value: attribute.Int64Value(req.GetId()), }) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - return nil, grpcutil.ProcessError(err) - } + request := types.DeleteFavoriteQueryRequest{ID: req.Id} - request := types.DeleteFavoriteQueryRequest{ - ID: req.Id, - ProfileID: profileID, - } - if err = a.service.DeleteFavoriteQuery(ctx, request); err != nil { + if err := a.service.DeleteFavoriteQuery(ctx, request); err != nil { return nil, grpcutil.ProcessError(err) } diff --git a/internal/api/userprofile/v1/grpc/favorite_queries_test.go b/internal/api/userprofile/v1/grpc/favorite_queries_test.go index b2e4f52..bf5e88f 100644 --- a/internal/api/userprofile/v1/grpc/favorite_queries_test.go +++ b/internal/api/userprofile/v1/grpc/favorite_queries_test.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,11 +14,6 @@ import ( ) func TestGetFavoriteQueries(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - queryName := "my query" - var relativeFrom uint64 = 300 - type mockArgs struct { req types.GetFavoriteQueriesRequest resp types.FavoriteQueries @@ -33,10 +27,9 @@ func TestGetFavoriteQueries(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", want: &userprofile.GetFavoriteQueriesResponse{ Queries: []*userprofile.GetFavoriteQueriesResponse_Query{ { @@ -65,9 +58,6 @@ func TestGetFavoriteQueries(t *testing.T) { }, wantCode: codes.OK, mockArgs: &mockArgs{ - req: types.GetFavoriteQueriesRequest{ - ProfileID: profileID, - }, resp: types.FavoriteQueries{ { ID: 1, @@ -95,40 +85,28 @@ func TestGetFavoriteQueries(t *testing.T) { }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_repo_random", + name: "err_svc", wantCode: codes.Internal, mockArgs: &mockArgs{ - req: types.GetFavoriteQueriesRequest{ - ProfileID: profileID, - }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newFavoriteQueriesTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetAll(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) + mockedSvc.EXPECT(). + GetFavoriteQueries(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) - } - - got, err := api.GetFavoriteQueries(ctx, &userprofile.GetFavoriteQueriesRequest{}) + got, err := api.GetFavoriteQueries(context.Background(), &userprofile.GetFavoriteQueriesRequest{}) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { @@ -141,13 +119,6 @@ func TestGetFavoriteQueries(t *testing.T) { } func TestCreateFavoriteQuery(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - var queryID int64 = 1 - query := "test" - queryName := "my query" - var relativeFrom uint64 = 300 - type mockArgs struct { req types.GetOrCreateFavoriteQueryRequest resp int64 @@ -162,10 +133,9 @@ func TestCreateFavoriteQuery(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &userprofile.CreateFavoriteQueryRequest{ Query: query, Name: &queryName, @@ -177,7 +147,6 @@ func TestCreateFavoriteQuery(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, Query: query, Name: queryName, RelativeFrom: relativeFrom, @@ -186,66 +155,32 @@ func TestCreateFavoriteQuery(t *testing.T) { }, }, { - name: "success_only_query", - req: &userprofile.CreateFavoriteQueryRequest{ - Query: query, - }, - want: &userprofile.CreateFavoriteQueryResponse{ - Id: queryID, - }, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, - Query: query, - }, - resp: queryID, - }, - }, - { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_empty_query", - req: &userprofile.CreateFavoriteQueryRequest{}, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_random", + name: "err_svc", req: &userprofile.CreateFavoriteQueryRequest{ Query: query, }, wantCode: codes.Internal, mockArgs: &mockArgs{ - req: types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, - Query: query, - }, - err: errors.New("random repo err"), + req: types.GetOrCreateFavoriteQueryRequest{Query: query}, + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newFavoriteQueriesTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetOrCreate(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetOrCreateFavoriteQuery(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - got, err := api.CreateFavoriteQuery(ctx, tt.req) + got, err := api.CreateFavoriteQuery(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { @@ -258,10 +193,6 @@ func TestCreateFavoriteQuery(t *testing.T) { } func TestDeleteFavoriteQuery(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - var queryID int64 = 100 - type mockArgs struct { req types.DeleteFavoriteQueryRequest err error @@ -275,10 +206,9 @@ func TestDeleteFavoriteQuery(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", req: &userprofile.DeleteFavoriteQueryRequest{ Id: queryID, }, @@ -286,57 +216,39 @@ func TestDeleteFavoriteQuery(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.DeleteFavoriteQueryRequest{ - ID: queryID, - ProfileID: profileID, + ID: queryID, }, }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_invalid_id", - req: &userprofile.DeleteFavoriteQueryRequest{ - Id: -100, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_random", + name: "err_svc", req: &userprofile.DeleteFavoriteQueryRequest{ Id: queryID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.DeleteFavoriteQueryRequest{ - ID: queryID, - ProfileID: profileID, + ID: queryID, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newFavoriteQueriesTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Delete(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + DeleteFavoriteQuery(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } - got, err := api.DeleteFavoriteQuery(ctx, tt.req) + got, err := api.DeleteFavoriteQuery(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) if tt.wantCode != codes.OK { diff --git a/internal/api/userprofile/v1/grpc/test_data.go b/internal/api/userprofile/v1/grpc/test_data.go index 2860f1a..6198a91 100644 --- a/internal/api/userprofile/v1/grpc/test_data.go +++ b/internal/api/userprofile/v1/grpc/test_data.go @@ -1,18 +1,35 @@ package grpc import ( + "context" + "errors" "testing" - "github.com/ozontech/seq-ui/internal/api/userprofile/v1/test" - repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/app/types" + mock "github.com/ozontech/seq-ui/internal/pkg/service/userprofile/mock" +) + +var ( + errSomethingWrong = errors.New("something happened wrong") + queryID int64 = 1 + relativeFrom uint64 = 300 + userName = "unnamed" + query = "test" + queryName = "my query" + timezone = "UTC" + validTimezone = "Europe/Moscow" + onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` + logColumns = []string{"val1", "val2"} ) -func newUserProfilesTestData(t *testing.T) (*API, *repo_mock.MockUserProfiles) { - mock, s, p := test.NewUserProfilesData(t) - return New(s, p), mock +func setupAPI(t *testing.T) (*API, *mock.MockService) { + ctrl := gomock.NewController(t) + mockedSvc := mock.NewMockService(ctrl) + return New(mockedSvc), mockedSvc } -func newFavoriteQueriesTestData(t *testing.T) (*API, *repo_mock.MockFavoriteQueries) { - mock, s, p := test.NewFavoriteQueriesTestData(t) - return New(s, p), mock +func withUser(userName string) context.Context { + return context.WithValue(context.Background(), types.UserKey{}, userName) } diff --git a/internal/api/userprofile/v1/grpc/user_profiles.go b/internal/api/userprofile/v1/grpc/user_profiles.go index 45371d2..550fd68 100644 --- a/internal/api/userprofile/v1/grpc/user_profiles.go +++ b/internal/api/userprofile/v1/grpc/user_profiles.go @@ -21,16 +21,13 @@ func (a *API) GetUserProfile(ctx context.Context, _ *userprofile.GetUserProfileR return nil, grpcutil.ProcessError(err) } - request := types.GetOrCreateUserProfileRequest{ - UserName: userName, - } + request := types.GetOrCreateUserProfileRequest{UserName: userName} + userProfile, err := a.service.GetOrCreateUserProfile(ctx, request) if err != nil { return nil, grpcutil.ProcessError(err) } - a.profiles.SetID(userName, userProfile.ID) - return userProfile.ToProto(), nil } @@ -60,6 +57,7 @@ func (a *API) UpdateUserProfile(ctx context.Context, req *userprofile.UpdateUser Timezone: req.Timezone, OnboardingVersion: req.OnboardingVersion, } + if req.GetLogColumns() != nil { request.LogColumns = &types.LogColumns{LogColumns: req.GetLogColumns().GetLogColumns()} } diff --git a/internal/api/userprofile/v1/grpc/user_profiles_test.go b/internal/api/userprofile/v1/grpc/user_profiles_test.go index 444db8b..125ba07 100644 --- a/internal/api/userprofile/v1/grpc/user_profiles_test.go +++ b/internal/api/userprofile/v1/grpc/user_profiles_test.go @@ -1,8 +1,6 @@ package grpc import ( - "context" - "errors" "testing" "github.com/stretchr/testify/require" @@ -15,11 +13,6 @@ import ( ) func TestGetUserProfile(t *testing.T) { - userName := "unnamed" - timezone := "UTC" - onboardingVersion := `{"name1": "ver1", "name2": "ver2"}` - logColumns := []string{"val1", "val2"} - type mockArgs struct { req types.GetOrCreateUserProfileRequest resp types.UserProfile @@ -33,10 +26,9 @@ func TestGetUserProfile(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success", + name: "ok", want: &userprofile.GetUserProfileResponse{ Timezone: timezone, OnboardingVersion: onboardingVersion, @@ -57,38 +49,31 @@ func TestGetUserProfile(t *testing.T) { }, }, { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_repo_random", + name: "err_svc", wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.GetOrCreateUserProfileRequest{ UserName: userName, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newUserProfilesTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetOrCreate(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + mockedSvc.EXPECT(). + GetOrCreateUserProfile(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } + ctx := withUser(userName) got, err := api.GetUserProfile(ctx, &userprofile.GetUserProfileRequest{}) require.Equal(t, tt.wantCode, status.Code(err)) @@ -102,12 +87,6 @@ func TestGetUserProfile(t *testing.T) { } func TestUpdateUserProfile(t *testing.T) { - userName := "unnamed" - validTimezone := "Europe/Moscow" - invalidTimezone := "invalid timezone" - onboardingVersion := `{"name1": "ver1", "name2": "ver2"}` - logColumns := []string{"val1", "val2"} - type mockArgs struct { req types.UpdateUserProfileRequest err error @@ -121,10 +100,9 @@ func TestUpdateUserProfile(t *testing.T) { wantCode codes.Code mockArgs *mockArgs - noUser bool }{ { - name: "success_all", + name: "ok", req: &userprofile.UpdateUserProfileRequest{ Timezone: &validTimezone, OnboardingVersion: &onboardingVersion, @@ -142,94 +120,7 @@ func TestUpdateUserProfile(t *testing.T) { }, }, { - name: "success_only_timezone", - req: &userprofile.UpdateUserProfileRequest{ - Timezone: &validTimezone, - }, - want: &userprofile.UpdateUserProfileResponse{}, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - Timezone: &validTimezone, - }, - }, - }, - { - name: "success_only_onboarding_ver", - req: &userprofile.UpdateUserProfileRequest{ - OnboardingVersion: &onboardingVersion, - }, - want: &userprofile.UpdateUserProfileResponse{}, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - OnboardingVersion: &onboardingVersion, - }, - }, - }, - { - name: "success_only_log_columns", - req: &userprofile.UpdateUserProfileRequest{ - LogColumns: &userprofile.LogColumns{LogColumns: logColumns}, - }, - want: &userprofile.UpdateUserProfileResponse{}, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - LogColumns: &types.LogColumns{LogColumns: logColumns}, - }, - }, - }, - { - name: "success_empty_log_columns", - req: &userprofile.UpdateUserProfileRequest{ - LogColumns: &userprofile.LogColumns{LogColumns: []string{}}, - }, - want: &userprofile.UpdateUserProfileResponse{}, - wantCode: codes.OK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - LogColumns: &types.LogColumns{LogColumns: []string{}}, - }, - }, - }, - { - name: "err_no_user", - wantCode: codes.Unauthenticated, - noUser: true, - }, - { - name: "err_svc_empty_request", - req: &userprofile.UpdateUserProfileRequest{}, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc_invalid_timezone_format", - req: &userprofile.UpdateUserProfileRequest{ - Timezone: &invalidTimezone, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_repo_not_found", - req: &userprofile.UpdateUserProfileRequest{ - Timezone: &validTimezone, - }, - wantCode: codes.NotFound, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - Timezone: &validTimezone, - }, - err: types.ErrNotFound, - }, - }, - { - name: "err_repo_random", + name: "err_svc", req: &userprofile.UpdateUserProfileRequest{ Timezone: &validTimezone, }, @@ -239,27 +130,25 @@ func TestUpdateUserProfile(t *testing.T) { UserName: userName, Timezone: &validTimezone, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newUserProfilesTestData(t) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Update(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - - ctx := context.Background() - if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + mockedSvc.EXPECT(). + UpdateUserProfile(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } + ctx := withUser(userName) got, err := api.UpdateUserProfile(ctx, tt.req) require.Equal(t, tt.wantCode, status.Code(err)) diff --git a/internal/api/userprofile/v1/http/api.go b/internal/api/userprofile/v1/http/api.go index b817660..08865be 100644 --- a/internal/api/userprofile/v1/http/api.go +++ b/internal/api/userprofile/v1/http/api.go @@ -3,19 +3,16 @@ package http import ( "github.com/go-chi/chi/v5" - "github.com/ozontech/seq-ui/internal/api/profiles" - "github.com/ozontech/seq-ui/internal/pkg/service" + userprofile "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" ) type API struct { - service service.Service - profiles *profiles.Profiles + service userprofile.Service } -func New(svc service.Service, p *profiles.Profiles) *API { +func New(svc userprofile.Service) *API { return &API{ - service: svc, - profiles: p, + service: svc, } } diff --git a/internal/api/userprofile/v1/http/favorite_queries.go b/internal/api/userprofile/v1/http/favorite_queries.go index 8a72eb7..ba638dd 100644 --- a/internal/api/userprofile/v1/http/favorite_queries.go +++ b/internal/api/userprofile/v1/http/favorite_queries.go @@ -29,16 +29,9 @@ func (a *API) serveGetFavoriteQueries(w http.ResponseWriter, r *http.Request) { wr := httputil.NewWriter(w) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } - - req := types.GetFavoriteQueriesRequest{ - ProfileID: profileID, - } + req := types.GetFavoriteQueriesRequest{} fqs, err := a.service.GetFavoriteQueries(ctx, req) + if err != nil { httputil.ProcessError(wr, err) return @@ -85,26 +78,20 @@ func (a *API) serveCreateFavoriteQuery(w http.ResponseWriter, r *http.Request) { }, ) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } + req := types.GetOrCreateFavoriteQueryRequest{Query: httpReq.Query} - req := types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, - Query: httpReq.Query, - } if httpReq.Name != nil { req.Name = *httpReq.Name } if httpReq.RelativeFrom != nil { + var err error req.RelativeFrom, err = strconv.ParseUint(*httpReq.RelativeFrom, 10, 64) if err != nil { wr.Error(errors.New("incorrect favorite query 'relativeFrom' format"), http.StatusBadRequest) return } } + fqID, err := a.service.GetOrCreateFavoriteQuery(ctx, req) if err != nil { httputil.ProcessError(wr, err) @@ -142,16 +129,8 @@ func (a *API) serveDeleteFavoriteQuery(w http.ResponseWriter, r *http.Request) { Value: attribute.Int64Value(id), }) - profileID, err := a.profiles.GeIDFromContext(ctx) - if err != nil { - httputil.ProcessError(wr, err) - return - } + req := types.DeleteFavoriteQueryRequest{ID: id} - req := types.DeleteFavoriteQueryRequest{ - ID: id, - ProfileID: profileID, - } err = a.service.DeleteFavoriteQuery(ctx, req) if err != nil { httputil.ProcessError(wr, err) diff --git a/internal/api/userprofile/v1/http/favorite_queries_test.go b/internal/api/userprofile/v1/http/favorite_queries_test.go index a280567..38d6242 100644 --- a/internal/api/userprofile/v1/http/favorite_queries_test.go +++ b/internal/api/userprofile/v1/http/favorite_queries_test.go @@ -1,15 +1,11 @@ package http import ( - "context" - "errors" "fmt" "net/http" - "net/http/httptest" - "strings" + "strconv" "testing" - "github.com/go-chi/chi/v5" "go.uber.org/mock/gomock" "github.com/ozontech/seq-ui/internal/api/httputil" @@ -17,8 +13,6 @@ import ( ) func TestServeGetFavoriteQueries(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 type mockArgs struct { req types.GetFavoriteQueriesRequest @@ -29,106 +23,64 @@ func TestServeGetFavoriteQueries(t *testing.T) { tests := []struct { name string - wantRespBody string - wantStatus int + want getFavoriteQueriesResponse + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - wantRespBody: `{"queries":[{"id":"1","query":"test1","name":"my query 1","relativeFrom":"300"},{"id":"2","query":"test2","name":"my query 2"},{"id":"3","query":"test3","relativeFrom":"900"},{"id":"4","query":"test4"}]}`, - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.GetFavoriteQueriesRequest{ - ProfileID: profileID, + name: "ok", + want: getFavoriteQueriesResponse{ + Queries: favoriteQueries{ + {ID: "1", Query: "test1", Name: "my query 1", RelativeFrom: relativeFrom}, + {ID: "2", Query: "test2", Name: "my query 2"}, + {ID: "3", Query: "test3", RelativeFrom: relativeFrom}, + {ID: "4", Query: "test4"}, }, + }, + mockArgs: &mockArgs{ resp: types.FavoriteQueries{ - { - ID: 1, - Query: "test1", - Name: "my query 1", - RelativeFrom: 300, - }, - { - ID: 2, - Query: "test2", - Name: "my query 2", - }, - { - ID: 3, - Query: "test3", - RelativeFrom: 900, - }, - { - ID: 4, - Query: "test4", - }, + {ID: 1, Query: "test1", Name: "my query 1", RelativeFrom: 300}, + {ID: 2, Query: "test2", Name: "my query 2"}, + {ID: 3, Query: "test3", RelativeFrom: 300}, + {ID: 4, Query: "test4"}, }, }, }, { - name: "err_no_user", - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_repo_random", - wantStatus: http.StatusInternalServerError, + name: "err_svc", + wantErr: true, mockArgs: &mockArgs{ - req: types.GetFavoriteQueriesRequest{ - ProfileID: profileID, - }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newFavoriteQueriesTestData(t) - req := httptest.NewRequest(http.MethodGet, "/userprofile/v1/queries/favorite", http.NoBody) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetAll(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetFavoriteQueries(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetFavoriteQueries, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFavoriteQueriesResponse]{ + Method: http.MethodGet, + Target: "/userprofile/v1/queries/favorite", + Handler: api.serveGetFavoriteQueries, + Want: tt.want, + WantErr: tt.wantErr, }) }) } } func TestServeCreateFavoriteQuery(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - var queryID int64 = 1 - query := "test" - - formatReqBody := func(query, name, relativeFrom string) string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf(`{"query":%q`, query)) - if name != "" { - sb.WriteString(fmt.Sprintf(`,"name":%q`, name)) - } - if relativeFrom != "" { - sb.WriteString(fmt.Sprintf(`,"relativeFrom":%q`, relativeFrom)) - } - sb.WriteString("}") - return sb.String() - } - type mockArgs struct { req types.GetOrCreateFavoriteQueryRequest resp int64 @@ -138,107 +90,66 @@ func TestServeCreateFavoriteQuery(t *testing.T) { tests := []struct { name string - reqBody string - wantRespBody string - wantStatus int + req createFavoriteQueryRequest + want createFavoriteQueryResponse + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - reqBody: formatReqBody(query, "my query", "300"), - wantRespBody: fmt.Sprintf(`{"id":"%d"}`, queryID), - wantStatus: http.StatusOK, + name: "ok", + req: createFavoriteQueryRequest{Query: query, Name: &queryName, RelativeFrom: &relativeFrom}, + want: createFavoriteQueryResponse{ID: "1"}, mockArgs: &mockArgs{ req: types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, Query: query, Name: "my query", RelativeFrom: 300, }, - resp: queryID, - }, - }, - { - name: "success_only_query", - reqBody: formatReqBody(query, "", ""), - wantRespBody: fmt.Sprintf(`{"id":"%d"}`, queryID), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, - Query: query, - }, - resp: queryID, + resp: 1, }, }, { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(query, "", ""), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_invalid_relative_from_format", - reqBody: formatReqBody(query, "", "not_number"), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_empty_query", - reqBody: formatReqBody("", "", ""), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_random", - reqBody: formatReqBody(query, "", ""), - wantStatus: http.StatusInternalServerError, + name: "err_svc", + req: createFavoriteQueryRequest{Query: query, Name: &queryName, RelativeFrom: &relativeFrom}, + wantErr: true, mockArgs: &mockArgs{ req: types.GetOrCreateFavoriteQueryRequest{ - ProfileID: profileID, - Query: query, + Query: query, + Name: "my query", + RelativeFrom: 300, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newFavoriteQueriesTestData(t) - req := httptest.NewRequest(http.MethodPost, "/userprofile/v1/queries/favorite", strings.NewReader(tt.reqBody)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetOrCreate(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + GetOrCreateFavoriteQuery(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveCreateFavoriteQuery, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[createFavoriteQueryRequest, createFavoriteQueryResponse]{ + Method: http.MethodPost, + Target: "/userprofile/v1/queries/favorite", + Req: tt.req, + Handler: api.serveCreateFavoriteQuery, + Want: tt.want, + WantErr: tt.wantErr, }) }) } } func TestServeDeleteFavoriteQuery(t *testing.T) { - userName := "unnamed" - var profileID int64 = 1 - type mockArgs struct { req types.DeleteFavoriteQueryRequest err error @@ -247,77 +158,52 @@ func TestServeDeleteFavoriteQuery(t *testing.T) { tests := []struct { name string - id string - wantStatus int + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - id: "100", - wantStatus: http.StatusOK, + name: "ok", mockArgs: &mockArgs{ req: types.DeleteFavoriteQueryRequest{ - ID: 100, - ProfileID: profileID, + ID: 100, }, }, }, { - name: "err_invalid_id_format", - id: "not_number", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - id: "100", - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_invalid_id", - id: "-100", - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_random", - id: "100", - wantStatus: http.StatusInternalServerError, + name: "err_svc", + wantErr: true, mockArgs: &mockArgs{ req: types.DeleteFavoriteQueryRequest{ - ID: 100, - ProfileID: profileID, + ID: 100, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newFavoriteQueriesTestData(t) - req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/userprofile/v1/queries/favorite/%s", tt.id), http.NoBody) - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("id", tt.id) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Delete(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) - api.profiles.SetID(userName, profileID) + mockedSvc.EXPECT(). + DeleteFavoriteQuery(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveDeleteFavoriteQuery, - WantStatus: tt.wantStatus, + id := strconv.FormatInt(tt.mockArgs.req.ID, 10) + handler := withID(api.serveDeleteFavoriteQuery, id) + + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ + Method: http.MethodDelete, + Target: fmt.Sprintf("/userprofile/v1/queries/favorite/%s", id), + Handler: handler, + NoResp: true, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/userprofile/v1/http/test_data.go b/internal/api/userprofile/v1/http/test_data.go index fcfb67a..69b4391 100644 --- a/internal/api/userprofile/v1/http/test_data.go +++ b/internal/api/userprofile/v1/http/test_data.go @@ -1,18 +1,48 @@ package http import ( + "context" + "errors" + "net/http" "testing" - "github.com/ozontech/seq-ui/internal/api/userprofile/v1/test" - repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" + "github.com/go-chi/chi/v5" + "go.uber.org/mock/gomock" + + "github.com/ozontech/seq-ui/internal/app/types" + mock "github.com/ozontech/seq-ui/internal/pkg/service/userprofile/mock" +) + +var ( + errSomethingWrong = errors.New("something happened wrong") + userName = "unnamed" + relativeFrom = "300" + query = "test" + queryName = "my query" + timezone = "UTC" + validTimezone = "Europe/Moscow" + onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` + logColumns = []string{"val1", "val2"} ) -func newUserProfilesTestData(t *testing.T) (*API, *repo_mock.MockUserProfiles) { - mock, s, p := test.NewUserProfilesData(t) - return New(s, p), mock +func setupAPI(t *testing.T) (*API, *mock.MockService) { + ctrl := gomock.NewController(t) + mockedSvc := mock.NewMockService(ctrl) + return New(mockedSvc), mockedSvc +} + +func withUser(h http.HandlerFunc, userName string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(context.WithValue(r.Context(), types.UserKey{}, userName)) + h(w, r) + } } -func newFavoriteQueriesTestData(t *testing.T) (*API, *repo_mock.MockFavoriteQueries) { - mock, s, p := test.NewFavoriteQueriesTestData(t) - return New(s, p), mock +func withID(h http.HandlerFunc, id string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + rCtx := chi.NewRouteContext() + rCtx.URLParams.Add("id", id) + r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rCtx)) + h(w, r) + } } diff --git a/internal/api/userprofile/v1/http/user_profiles.go b/internal/api/userprofile/v1/http/user_profiles.go index e008f0b..e116c67 100644 --- a/internal/api/userprofile/v1/http/user_profiles.go +++ b/internal/api/userprofile/v1/http/user_profiles.go @@ -35,14 +35,13 @@ func (a *API) serveGetUserProfile(w http.ResponseWriter, r *http.Request) { req := types.GetOrCreateUserProfileRequest{ UserName: userName, } + up, err := a.service.GetOrCreateUserProfile(ctx, req) if err != nil { httputil.ProcessError(wr, err) return } - a.profiles.SetID(userName, up.ID) - wr.WriteJson(newUserProfile(up)) } @@ -93,6 +92,7 @@ func (a *API) serveUpdateUserProfile(w http.ResponseWriter, r *http.Request) { Timezone: httpReq.Timezone, OnboardingVersion: httpReq.OnboardingVersion, } + if httpReq.LogColumns != nil { req.LogColumns = &types.LogColumns{LogColumns: httpReq.LogColumns.Columns} } diff --git a/internal/api/userprofile/v1/http/user_profiles_test.go b/internal/api/userprofile/v1/http/user_profiles_test.go index 2cdfd30..5a31351 100644 --- a/internal/api/userprofile/v1/http/user_profiles_test.go +++ b/internal/api/userprofile/v1/http/user_profiles_test.go @@ -1,13 +1,7 @@ package http import ( - "context" - "encoding/json" - "errors" - "fmt" "net/http" - "net/http/httptest" - "strings" "testing" "go.uber.org/mock/gomock" @@ -17,11 +11,6 @@ import ( ) func TestServeGetUserProfile(t *testing.T) { - userName := "unnamed" - timezone := "UTC" - onboardingVersion := `{"name1": "ver1", "name2": "ver2"}` - logColumns := []string{"val1", "val2"} - type mockArgs struct { req types.GetOrCreateUserProfileRequest resp types.UserProfile @@ -31,16 +20,18 @@ func TestServeGetUserProfile(t *testing.T) { tests := []struct { name string - wantRespBody string - wantStatus int + want userProfile + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success", - wantRespBody: `{"timezone":"UTC","onboardingVersion":"{\"name1\": \"ver1\", \"name2\": \"ver2\"}","log_columns":["val1","val2"]}`, - wantStatus: http.StatusOK, + name: "ok", + want: userProfile{ + Timezone: timezone, + OnboardingVersion: onboardingVersion, + LogColumns: logColumns, + }, mockArgs: &mockArgs{ req: types.GetOrCreateUserProfileRequest{ UserName: userName, @@ -55,77 +46,42 @@ func TestServeGetUserProfile(t *testing.T) { }, }, { - name: "err_no_user", - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_repo_random", - wantStatus: http.StatusInternalServerError, + name: "err_svc", + wantErr: true, mockArgs: &mockArgs{ req: types.GetOrCreateUserProfileRequest{ UserName: userName, }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newUserProfilesTestData(t) - req := httptest.NewRequest(http.MethodGet, "/userprofile/v1/profile", http.NoBody) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().GetOrCreate(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + mockedSvc.EXPECT(). + GetOrCreateUserProfile(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.resp, tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveGetUserProfile, - WantRespBody: tt.wantRespBody, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, userProfile]{ + Method: http.MethodGet, + Target: "/userprofile/v1/profile", + Handler: withUser(api.serveGetUserProfile, userName), + Want: tt.want, + WantErr: tt.wantErr, }) }) } } func TestServeUpdateUserProfile(t *testing.T) { - userName := "unnamed" - validTimezone := "Europe/Moscow" - invalidTimezone := "invalid timezone" - onboardingVersion := `{"name1": "ver1", "name2": "ver2"}` - logColumns := []string{"val1", "val2"} - - formatReqBody := func(timezone, onboardingVersion string, logColumns []string) string { - var sb strings.Builder - sb.WriteString("{") - if timezone != "" { - sb.WriteString(fmt.Sprintf(`"timezone":%q`, timezone)) - } - if onboardingVersion != "" { - if sb.Len() > 1 { - sb.WriteString(",") - } - sb.WriteString(fmt.Sprintf(`"onboardingVersion":%q`, onboardingVersion)) - } - if logColumns != nil { - if sb.Len() > 1 { - sb.WriteString(",") - } - v, _ := json.Marshal(logColumns) - sb.WriteString(fmt.Sprintf(`"log_columns":{"columns":%s}`, v)) - } - sb.WriteString("}") - return sb.String() - } - type mockArgs struct { req types.UpdateUserProfileRequest err error @@ -134,16 +90,20 @@ func TestServeUpdateUserProfile(t *testing.T) { tests := []struct { name string - reqBody string - wantStatus int + req updateUserProfileRequest + wantErr bool mockArgs *mockArgs - noUser bool }{ { - name: "success_all", - reqBody: formatReqBody(validTimezone, onboardingVersion, logColumns), - wantStatus: http.StatusOK, + name: "ok", + req: updateUserProfileRequest{ + Timezone: &validTimezone, + OnboardingVersion: &onboardingVersion, + LogColumns: &struct { + Columns []string "json:\"columns\"" + }{Columns: logColumns}, + }, mockArgs: &mockArgs{ req: types.UpdateUserProfileRequest{ UserName: userName, @@ -154,116 +114,47 @@ func TestServeUpdateUserProfile(t *testing.T) { }, }, { - name: "success_only_timezone", - reqBody: formatReqBody(validTimezone, "", nil), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - Timezone: &validTimezone, - }, + name: "err_svc", + req: updateUserProfileRequest{ + Timezone: &validTimezone, + OnboardingVersion: &onboardingVersion, + LogColumns: &struct { + Columns []string "json:\"columns\"" + }{Columns: logColumns}, }, - }, - { - name: "success_only_onboarding_ver", - reqBody: formatReqBody("", onboardingVersion, nil), - wantStatus: http.StatusOK, + wantErr: true, mockArgs: &mockArgs{ req: types.UpdateUserProfileRequest{ UserName: userName, + Timezone: &validTimezone, OnboardingVersion: &onboardingVersion, + LogColumns: &types.LogColumns{LogColumns: logColumns}, }, - }, - }, - { - name: "success_only_log_columns", - reqBody: formatReqBody("", "", logColumns), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - LogColumns: &types.LogColumns{LogColumns: logColumns}, - }, - }, - }, - { - name: "success_empty_log_columns", - reqBody: formatReqBody("", "", []string{}), - wantStatus: http.StatusOK, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - LogColumns: &types.LogColumns{LogColumns: []string{}}, - }, - }, - }, - { - name: "err_invalid_request", - reqBody: "invalid-request", - wantStatus: http.StatusBadRequest, - noUser: true, - }, - { - name: "err_no_user", - reqBody: formatReqBody(validTimezone, "", nil), - wantStatus: http.StatusUnauthorized, - noUser: true, - }, - { - name: "err_svc_empty_request", - reqBody: `{}`, - wantStatus: http.StatusBadRequest, - }, - { - name: "err_svc_invalid_timezone_format", - reqBody: formatReqBody(invalidTimezone, "", nil), - wantStatus: http.StatusBadRequest, - }, - { - name: "err_repo_not_found", - reqBody: formatReqBody(validTimezone, "", nil), - wantStatus: http.StatusNotFound, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - Timezone: &validTimezone, - }, - err: types.ErrNotFound, - }, - }, - { - name: "err_repo_random", - reqBody: formatReqBody(validTimezone, "", nil), - wantStatus: http.StatusInternalServerError, - mockArgs: &mockArgs{ - req: types.UpdateUserProfileRequest{ - UserName: userName, - Timezone: &validTimezone, - }, - err: errors.New("random repo err"), + err: errSomethingWrong, }, }, } + for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := newUserProfilesTestData(t) - req := httptest.NewRequest(http.MethodPatch, "/userprofile/v1/profile", strings.NewReader(tt.reqBody)) + api, mockedSvc := setupAPI(t) if tt.mockArgs != nil { - mockedRepo.EXPECT().Update(gomock.Any(), tt.mockArgs.req). - Return(tt.mockArgs.err).Times(1) - } - if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + mockedSvc.EXPECT(). + UpdateUserProfile(gomock.Any(), tt.mockArgs.req). + Return(tt.mockArgs.err). + Times(1) } - httputil.DoTestHTTP(t, httputil.TestDataHTTP{ - Req: req, - Handler: api.serveUpdateUserProfile, - WantStatus: tt.wantStatus, + httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[updateUserProfileRequest, struct{}]{ + Method: http.MethodPatch, + Target: "/userprofile/v1/profile", + Req: tt.req, + Handler: withUser(api.serveUpdateUserProfile, userName), + NoResp: true, + WantErr: tt.wantErr, }) }) } diff --git a/internal/api/userprofile/v1/test/data.go b/internal/api/userprofile/v1/test/data.go deleted file mode 100644 index 9df8edc..0000000 --- a/internal/api/userprofile/v1/test/data.go +++ /dev/null @@ -1,34 +0,0 @@ -package test - -import ( - "testing" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/profiles" - repo "github.com/ozontech/seq-ui/internal/pkg/repository" - repo_mock "github.com/ozontech/seq-ui/internal/pkg/repository/mock" - "github.com/ozontech/seq-ui/internal/pkg/service" -) - -func NewUserProfilesData(t *testing.T) (*repo_mock.MockUserProfiles, service.Service, *profiles.Profiles) { - ctl := gomock.NewController(t) - mockedRepo := repo_mock.NewMockUserProfiles(ctl) - r := &repo.Repository{ - UserProfiles: mockedRepo, - } - s := service.New(r) - p := profiles.New(s) - return mockedRepo, s, p -} - -func NewFavoriteQueriesTestData(t *testing.T) (*repo_mock.MockFavoriteQueries, service.Service, *profiles.Profiles) { - ctl := gomock.NewController(t) - mockedRepo := repo_mock.NewMockFavoriteQueries(ctl) - r := &repo.Repository{ - FavoriteQueries: mockedRepo, - } - s := service.New(r) - p := profiles.New(s) - return mockedRepo, s, p -} diff --git a/internal/api/userprofile/v1/userprofile.go b/internal/api/userprofile/v1/userprofile.go index 66f5320..fe0cccd 100644 --- a/internal/api/userprofile/v1/userprofile.go +++ b/internal/api/userprofile/v1/userprofile.go @@ -3,10 +3,9 @@ package userprofile_v1 import ( "github.com/go-chi/chi/v5" - "github.com/ozontech/seq-ui/internal/api/profiles" grpc_api "github.com/ozontech/seq-ui/internal/api/userprofile/v1/grpc" http_api "github.com/ozontech/seq-ui/internal/api/userprofile/v1/http" - "github.com/ozontech/seq-ui/internal/pkg/service" + userprofile "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" ) type UserProfile struct { @@ -14,10 +13,10 @@ type UserProfile struct { httpAPI *http_api.API } -func New(svc service.Service, p *profiles.Profiles) *UserProfile { +func New(up userprofile.Service) *UserProfile { return &UserProfile{ - grpcAPI: grpc_api.New(svc, p), - httpAPI: http_api.New(svc, p), + grpcAPI: grpc_api.New(up), + httpAPI: http_api.New(up), } } diff --git a/internal/app/auth/oidc.go b/internal/app/auth/oidc.go index 4b9fdbd..15caf35 100644 --- a/internal/app/auth/oidc.go +++ b/internal/app/auth/oidc.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "net/http" + "slices" "time" "github.com/coreos/go-oidc/v3/oidc" @@ -169,10 +170,8 @@ func (p *oidcProvider) checkClients(clients []string) error { } for _, client := range clients { - for _, allowedClient := range p.allowedClients { - if client == allowedClient { - return nil - } + if slices.Contains(p.allowedClients, client) { + return nil } } diff --git a/internal/pkg/service/async_searches/mock/service.go b/internal/pkg/service/async_searches/mock/service.go new file mode 100644 index 0000000..4349018 --- /dev/null +++ b/internal/pkg/service/async_searches/mock/service.go @@ -0,0 +1,117 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ozontech/seq-ui/internal/pkg/service/async_searches (interfaces: Service) +// +// Generated by this command: +// +// mockgen -destination=internal/pkg/service/async_searches/mock/service.go github.com/ozontech/seq-ui/internal/pkg/service/async_searches Service +// + +// Package mock_asyncsearches is a generated GoMock package. +package mock_asyncsearches + +import ( + context "context" + reflect "reflect" + + seqapi "github.com/ozontech/seq-ui/pkg/seqapi/v1" + gomock "go.uber.org/mock/gomock" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder + isgomock struct{} +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// CancelAsyncSearch mocks base method. +func (m *MockService) CancelAsyncSearch(arg0 context.Context, arg1 *seqapi.CancelAsyncSearchRequest) (*seqapi.CancelAsyncSearchResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CancelAsyncSearch", arg0, arg1) + ret0, _ := ret[0].(*seqapi.CancelAsyncSearchResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CancelAsyncSearch indicates an expected call of CancelAsyncSearch. +func (mr *MockServiceMockRecorder) CancelAsyncSearch(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelAsyncSearch", reflect.TypeOf((*MockService)(nil).CancelAsyncSearch), arg0, arg1) +} + +// DeleteAsyncSearch mocks base method. +func (m *MockService) DeleteAsyncSearch(arg0 context.Context, arg1 *seqapi.DeleteAsyncSearchRequest) (*seqapi.DeleteAsyncSearchResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAsyncSearch", arg0, arg1) + ret0, _ := ret[0].(*seqapi.DeleteAsyncSearchResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteAsyncSearch indicates an expected call of DeleteAsyncSearch. +func (mr *MockServiceMockRecorder) DeleteAsyncSearch(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAsyncSearch", reflect.TypeOf((*MockService)(nil).DeleteAsyncSearch), arg0, arg1) +} + +// FetchAsyncSearchResult mocks base method. +func (m *MockService) FetchAsyncSearchResult(arg0 context.Context, arg1 *seqapi.FetchAsyncSearchResultRequest) (*seqapi.FetchAsyncSearchResultResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchAsyncSearchResult", arg0, arg1) + ret0, _ := ret[0].(*seqapi.FetchAsyncSearchResultResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchAsyncSearchResult indicates an expected call of FetchAsyncSearchResult. +func (mr *MockServiceMockRecorder) FetchAsyncSearchResult(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchAsyncSearchResult", reflect.TypeOf((*MockService)(nil).FetchAsyncSearchResult), arg0, arg1) +} + +// GetAsyncSearchesList mocks base method. +func (m *MockService) GetAsyncSearchesList(arg0 context.Context, arg1 *seqapi.GetAsyncSearchesListRequest) (*seqapi.GetAsyncSearchesListResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAsyncSearchesList", arg0, arg1) + ret0, _ := ret[0].(*seqapi.GetAsyncSearchesListResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAsyncSearchesList indicates an expected call of GetAsyncSearchesList. +func (mr *MockServiceMockRecorder) GetAsyncSearchesList(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAsyncSearchesList", reflect.TypeOf((*MockService)(nil).GetAsyncSearchesList), arg0, arg1) +} + +// StartAsyncSearch mocks base method. +func (m *MockService) StartAsyncSearch(arg0 context.Context, arg1 *seqapi.StartAsyncSearchRequest) (*seqapi.StartAsyncSearchResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StartAsyncSearch", arg0, arg1) + ret0, _ := ret[0].(*seqapi.StartAsyncSearchResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StartAsyncSearch indicates an expected call of StartAsyncSearch. +func (mr *MockServiceMockRecorder) StartAsyncSearch(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartAsyncSearch", reflect.TypeOf((*MockService)(nil).StartAsyncSearch), arg0, arg1) +} diff --git a/internal/pkg/service/async_searches/service.go b/internal/pkg/service/async_searches/service.go index 0960785..d6f4825 100644 --- a/internal/pkg/service/async_searches/service.go +++ b/internal/pkg/service/async_searches/service.go @@ -14,6 +14,7 @@ import ( "github.com/ozontech/seq-ui/internal/app/types" "github.com/ozontech/seq-ui/internal/pkg/client/seqdb" "github.com/ozontech/seq-ui/internal/pkg/repository" + "github.com/ozontech/seq-ui/internal/pkg/service/profiles" "github.com/ozontech/seq-ui/logger" "github.com/ozontech/seq-ui/metric" "github.com/ozontech/seq-ui/pkg/seqapi/v1" @@ -26,20 +27,23 @@ const ( deleteExpiredAsyncSearchesInterval = 1 * time.Minute ) -type Service struct { +type Service interface { + StartAsyncSearch(context.Context, *seqapi.StartAsyncSearchRequest) (*seqapi.StartAsyncSearchResponse, error) + DeleteAsyncSearch(context.Context, *seqapi.DeleteAsyncSearchRequest) (*seqapi.DeleteAsyncSearchResponse, error) + CancelAsyncSearch(context.Context, *seqapi.CancelAsyncSearchRequest) (*seqapi.CancelAsyncSearchResponse, error) + FetchAsyncSearchResult(context.Context, *seqapi.FetchAsyncSearchResultRequest) (*seqapi.FetchAsyncSearchResultResponse, error) + GetAsyncSearchesList(context.Context, *seqapi.GetAsyncSearchesListRequest) (*seqapi.GetAsyncSearchesListResponse, error) +} + +type service struct { repo repository.AsyncSearches seqDB seqdb.Client cfg config.AsyncSearch } -func New( - ctx context.Context, - repo repository.AsyncSearches, - seqDB seqdb.Client, - cfg config.AsyncSearch, -) *Service { - s := &Service{ +func New(ctx context.Context, repo repository.AsyncSearches, seqDB seqdb.Client, cfg config.AsyncSearch) Service { + s := &service{ repo: repo, seqDB: seqDB, cfg: cfg, @@ -50,11 +54,12 @@ func New( return s } -func (s *Service) StartAsyncSearch( - ctx context.Context, - ownerID int64, - req *seqapi.StartAsyncSearchRequest, -) (*seqapi.StartAsyncSearchResponse, error) { +func (s *service) StartAsyncSearch(ctx context.Context, req *seqapi.StartAsyncSearchRequest) (*seqapi.StartAsyncSearchResponse, error) { + ownerID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return nil, err + } + if utf8.RuneCountInString(req.Query) > s.cfg.ListQueryLengthLimit { metric.AsyncSearchQueryTooLong.Inc() } @@ -82,11 +87,12 @@ func (s *Service) StartAsyncSearch( return resp, nil } -func (s *Service) DeleteAsyncSearch( - ctx context.Context, - ownerID int64, - req *seqapi.DeleteAsyncSearchRequest, -) (*seqapi.DeleteAsyncSearchResponse, error) { +func (s *service) DeleteAsyncSearch(ctx context.Context, req *seqapi.DeleteAsyncSearchRequest) (*seqapi.DeleteAsyncSearchResponse, error) { + ownerID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return nil, err + } + searchInfo, err := s.repo.GetAsyncSearchById(ctx, req.SearchId) if err != nil { return nil, fmt.Errorf("failed to get async search by id: %w", err) @@ -115,11 +121,12 @@ func (s *Service) DeleteAsyncSearch( return resp, nil } -func (s *Service) CancelAsyncSearch( - ctx context.Context, - ownerID int64, - req *seqapi.CancelAsyncSearchRequest, -) (*seqapi.CancelAsyncSearchResponse, error) { +func (s *service) CancelAsyncSearch(ctx context.Context, req *seqapi.CancelAsyncSearchRequest) (*seqapi.CancelAsyncSearchResponse, error) { + ownerID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return nil, err + } + searchInfo, err := s.repo.GetAsyncSearchById(ctx, req.SearchId) if err != nil { return nil, fmt.Errorf("failed to get async search by id: %w", err) @@ -137,10 +144,7 @@ func (s *Service) CancelAsyncSearch( return resp, nil } -func (s *Service) FetchAsyncSearchResult( - ctx context.Context, - req *seqapi.FetchAsyncSearchResultRequest, -) (*seqapi.FetchAsyncSearchResultResponse, error) { +func (s *service) FetchAsyncSearchResult(ctx context.Context, req *seqapi.FetchAsyncSearchResultRequest) (*seqapi.FetchAsyncSearchResultResponse, error) { searchInfo, err := s.repo.GetAsyncSearchById(ctx, req.SearchId) if err != nil { return nil, fmt.Errorf("failed to get async search by id: %w", err) @@ -156,10 +160,7 @@ func (s *Service) FetchAsyncSearchResult( return resp, nil } -func (s *Service) GetAsyncSearchesList( - ctx context.Context, - req *seqapi.GetAsyncSearchesListRequest, -) (*seqapi.GetAsyncSearchesListResponse, error) { +func (s *service) GetAsyncSearchesList(ctx context.Context, req *seqapi.GetAsyncSearchesListRequest) (*seqapi.GetAsyncSearchesListResponse, error) { searches, err := s.repo.GetAsyncSearchesList(ctx, types.GetAsyncSearchesListRequest{ Owner: req.OwnerName, }) @@ -191,7 +192,7 @@ func (s *Service) GetAsyncSearchesList( return resp, nil } -func (s *Service) isAdmin(ctx context.Context) bool { +func (s *service) isAdmin(ctx context.Context) bool { userName, err := types.GetUserKey(ctx) if err != nil { return false @@ -200,7 +201,7 @@ func (s *Service) isAdmin(ctx context.Context) bool { return slices.Index(s.cfg.AdminUsers, userName) >= 0 } -func (s *Service) deleteExpiredAsyncSearches(ctx context.Context) { +func (s *service) deleteExpiredAsyncSearches(ctx context.Context) { ticker := time.NewTicker(deleteExpiredAsyncSearchesInterval) defer ticker.Stop() @@ -217,7 +218,7 @@ func (s *Service) deleteExpiredAsyncSearches(ctx context.Context) { } } -func (s *Service) trimQueryToLimit(query string, limit int) string { +func (s *service) trimQueryToLimit(query string, limit int) string { count := 0 for i := range query { if count == limit { diff --git a/internal/pkg/service/dashboards/service.go b/internal/pkg/service/dashboards/service.go index 1d68c10..c84bd69 100644 --- a/internal/pkg/service/dashboards/service.go +++ b/internal/pkg/service/dashboards/service.go @@ -4,8 +4,10 @@ import ( "context" "github.com/gofrs/uuid" + "github.com/ozontech/seq-ui/internal/app/types" "github.com/ozontech/seq-ui/internal/pkg/repository" + "github.com/ozontech/seq-ui/internal/pkg/service/profiles" ) type Service interface { @@ -22,7 +24,18 @@ type service struct { repo repository.Dashboards } +func New(repo repository.Dashboards) Service { + return &service{ + repo: repo, + } +} + func (s *service) GetAllDashboards(ctx context.Context, req types.GetAllDashboardsRequest) (types.DashboardInfosWithOwner, error) { + // check auth and create profile if its doesn't exist + if _, err := profiles.GetIDFromContext(ctx); err != nil { + return nil, err + } + if err := checkLimitOffset(req.Limit, req.Offset); err != nil { return nil, err } @@ -31,6 +44,12 @@ func (s *service) GetAllDashboards(ctx context.Context, req types.GetAllDashboar } func (s *service) GetMyDashboards(ctx context.Context, req types.GetUserDashboardsRequest) (types.DashboardInfos, error) { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return nil, err + } + req.ProfileID = profileID + if err := checkLimitOffset(req.Limit, req.Offset); err != nil { return nil, err } @@ -39,6 +58,11 @@ func (s *service) GetMyDashboards(ctx context.Context, req types.GetUserDashboar } func (s *service) GetDashboardByUUID(ctx context.Context, id string) (types.Dashboard, error) { + // check auth and create profile if its doesn't exist + if _, err := profiles.GetIDFromContext(ctx); err != nil { + return types.Dashboard{}, err + } + if err := checkUUID(id); err != nil { return types.Dashboard{}, err } @@ -47,6 +71,12 @@ func (s *service) GetDashboardByUUID(ctx context.Context, id string) (types.Dash } func (s *service) CreateDashboard(ctx context.Context, req types.CreateDashboardRequest) (string, error) { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return "", err + } + req.ProfileID = profileID + if req.Name == "" { return "", types.NewErrInvalidRequestField("empty 'name'") } @@ -58,6 +88,12 @@ func (s *service) CreateDashboard(ctx context.Context, req types.CreateDashboard } func (s *service) UpdateDashboard(ctx context.Context, req types.UpdateDashboardRequest) error { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return err + } + req.ProfileID = profileID + if err := checkUUID(req.UUID); err != nil { return err } @@ -69,6 +105,12 @@ func (s *service) UpdateDashboard(ctx context.Context, req types.UpdateDashboard } func (s *service) DeleteDashboard(ctx context.Context, req types.DeleteDashboardRequest) error { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return err + } + req.ProfileID = profileID + if err := checkUUID(req.UUID); err != nil { return err } @@ -77,9 +119,15 @@ func (s *service) DeleteDashboard(ctx context.Context, req types.DeleteDashboard } func (s *service) SearchDashboards(ctx context.Context, req types.SearchDashboardsRequest) (types.DashboardInfosWithOwner, error) { + // check auth and create profile if its doesn't exist + if _, err := profiles.GetIDFromContext(ctx); err != nil { + return nil, err + } + if err := checkLimitOffset(req.Limit, req.Offset); err != nil { return nil, err } + return s.repo.Search(ctx, req) } diff --git a/internal/pkg/service/favorite_queries.go b/internal/pkg/service/favorite_queries.go deleted file mode 100644 index 9da4b5e..0000000 --- a/internal/pkg/service/favorite_queries.go +++ /dev/null @@ -1,30 +0,0 @@ -package service - -import ( - "context" - - "github.com/ozontech/seq-ui/internal/app/types" -) - -// GetFavoriteQueries from underlying repository. -func (s *service) GetFavoriteQueries(ctx context.Context, req types.GetFavoriteQueriesRequest) (types.FavoriteQueries, error) { - return s.repo.FavoriteQueries.GetAll(ctx, req) -} - -// GetOrCreateFavoriteQuery in underlying repository. -func (s *service) GetOrCreateFavoriteQuery(ctx context.Context, req types.GetOrCreateFavoriteQueryRequest) (int64, error) { - if req.Query == "" { - return -1, types.NewErrInvalidRequestField("empty query") - } - - return s.repo.FavoriteQueries.GetOrCreate(ctx, req) -} - -// DeleteFavoriteQuery in underlying repository. -func (s *service) DeleteFavoriteQuery(ctx context.Context, req types.DeleteFavoriteQueryRequest) error { - if req.ID <= 0 { - return types.NewErrInvalidRequestField("invalid id") - } - - return s.repo.FavoriteQueries.Delete(ctx, req) -} diff --git a/internal/pkg/service/massexport/mock/service.go b/internal/pkg/service/massexport/mock/service.go new file mode 100644 index 0000000..02928a0 --- /dev/null +++ b/internal/pkg/service/massexport/mock/service.go @@ -0,0 +1,115 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ozontech/seq-ui/internal/pkg/service/massexport (interfaces: Service) +// +// Generated by this command: +// +// mockgen -destination=internal/pkg/service/massexport/mock/service.go github.com/ozontech/seq-ui/internal/pkg/service/massexport Service +// + +// Package mock_massexport is a generated GoMock package. +package mock_massexport + +import ( + context "context" + reflect "reflect" + + types "github.com/ozontech/seq-ui/internal/app/types" + gomock "go.uber.org/mock/gomock" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder + isgomock struct{} +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// CancelExport mocks base method. +func (m *MockService) CancelExport(ctx context.Context, sessionID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CancelExport", ctx, sessionID) + ret0, _ := ret[0].(error) + return ret0 +} + +// CancelExport indicates an expected call of CancelExport. +func (mr *MockServiceMockRecorder) CancelExport(ctx, sessionID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelExport", reflect.TypeOf((*MockService)(nil).CancelExport), ctx, sessionID) +} + +// CheckExport mocks base method. +func (m *MockService) CheckExport(ctx context.Context, sessionID string) (types.ExportInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckExport", ctx, sessionID) + ret0, _ := ret[0].(types.ExportInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CheckExport indicates an expected call of CheckExport. +func (mr *MockServiceMockRecorder) CheckExport(ctx, sessionID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckExport", reflect.TypeOf((*MockService)(nil).CheckExport), ctx, sessionID) +} + +// GetAll mocks base method. +func (m *MockService) GetAll(ctx context.Context) ([]types.ExportInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAll", ctx) + ret0, _ := ret[0].([]types.ExportInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAll indicates an expected call of GetAll. +func (mr *MockServiceMockRecorder) GetAll(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAll", reflect.TypeOf((*MockService)(nil).GetAll), ctx) +} + +// RestoreExport mocks base method. +func (m *MockService) RestoreExport(ctx context.Context, sessionID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RestoreExport", ctx, sessionID) + ret0, _ := ret[0].(error) + return ret0 +} + +// RestoreExport indicates an expected call of RestoreExport. +func (mr *MockServiceMockRecorder) RestoreExport(ctx, sessionID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestoreExport", reflect.TypeOf((*MockService)(nil).RestoreExport), ctx, sessionID) +} + +// StartExport mocks base method. +func (m *MockService) StartExport(ctx context.Context, req types.StartExportRequest) (types.StartExportResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StartExport", ctx, req) + ret0, _ := ret[0].(types.StartExportResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StartExport indicates an expected call of StartExport. +func (mr *MockServiceMockRecorder) StartExport(ctx, req any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartExport", reflect.TypeOf((*MockService)(nil).StartExport), ctx, req) +} diff --git a/internal/api/profiles/profiles.go b/internal/pkg/service/profiles/profiles.go similarity index 71% rename from internal/api/profiles/profiles.go rename to internal/pkg/service/profiles/profiles.go index 616a966..abe8d0e 100644 --- a/internal/api/profiles/profiles.go +++ b/internal/pkg/service/profiles/profiles.go @@ -5,17 +5,26 @@ import ( "sync" "github.com/ozontech/seq-ui/internal/app/types" - "github.com/ozontech/seq-ui/internal/pkg/service" ) +type UserProfileService interface { + GetOrCreateUserProfile(context.Context, types.GetOrCreateUserProfileRequest) (types.UserProfile, error) +} + +var profile *Profiles + +func InitProfiles(svc UserProfileService) { + profile = New(svc) +} + type Profiles struct { idByName map[string]int64 // map UserName->UserProfileId mx sync.RWMutex - service service.Service + service UserProfileService } -func New(svc service.Service) *Profiles { +func New(svc UserProfileService) *Profiles { return &Profiles{ idByName: make(map[string]int64), service: svc, @@ -77,3 +86,11 @@ func (p *Profiles) SetID(userName string, userProfileID int64) { p.idByName[userName] = userProfileID } } + +func GetIDFromContext(ctx context.Context) (int64, error) { + return profile.GeIDFromContext(ctx) +} + +func SetID(userName string, userProfileID int64) { + profile.SetID(userName, userProfileID) +} diff --git a/internal/pkg/service/service.go b/internal/pkg/service/service.go deleted file mode 100644 index e8e2140..0000000 --- a/internal/pkg/service/service.go +++ /dev/null @@ -1,27 +0,0 @@ -package service - -import ( - "context" - - "github.com/ozontech/seq-ui/internal/app/types" - "github.com/ozontech/seq-ui/internal/pkg/repository" -) - -type Service interface { - GetOrCreateUserProfile(context.Context, types.GetOrCreateUserProfileRequest) (types.UserProfile, error) - UpdateUserProfile(context.Context, types.UpdateUserProfileRequest) error - - GetFavoriteQueries(context.Context, types.GetFavoriteQueriesRequest) (types.FavoriteQueries, error) - GetOrCreateFavoriteQuery(context.Context, types.GetOrCreateFavoriteQueryRequest) (int64, error) - DeleteFavoriteQuery(context.Context, types.DeleteFavoriteQueryRequest) error -} - -type service struct { - repo *repository.Repository -} - -func New(repo *repository.Repository) Service { - return &service{ - repo: repo, - } -} diff --git a/internal/pkg/service/user_profiles.go b/internal/pkg/service/user_profiles.go deleted file mode 100644 index e36685d..0000000 --- a/internal/pkg/service/user_profiles.go +++ /dev/null @@ -1,27 +0,0 @@ -package service - -import ( - "context" - "time" - - "github.com/ozontech/seq-ui/internal/app/types" -) - -// GetOrCreateUserProfile from underlying repository. -func (s *service) GetOrCreateUserProfile(ctx context.Context, req types.GetOrCreateUserProfileRequest) (types.UserProfile, error) { - return s.repo.UserProfiles.GetOrCreate(ctx, req) -} - -// UpdateUserProfile in underlying repository. -func (s *service) UpdateUserProfile(ctx context.Context, req types.UpdateUserProfileRequest) error { - if req.IsEmpty() { - return types.ErrEmptyUpdateRequest - } - if req.Timezone != nil { - if _, err := time.LoadLocation(*req.Timezone); err != nil { - return types.NewErrInvalidRequestField("invalid timezone format") - } - } - - return s.repo.UserProfiles.Update(ctx, req) -} diff --git a/internal/pkg/service/userprofile/mock/service.go b/internal/pkg/service/userprofile/mock/service.go new file mode 100644 index 0000000..b48115f --- /dev/null +++ b/internal/pkg/service/userprofile/mock/service.go @@ -0,0 +1,115 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ozontech/seq-ui/internal/pkg/service/userprofile (interfaces: Service) +// +// Generated by this command: +// +// mockgen -destination=internal/pkg/service/userprofile/mock/service.go github.com/ozontech/seq-ui/internal/pkg/service/userprofile Service +// + +// Package mock_userprofiles is a generated GoMock package. +package mock_userprofiles + +import ( + context "context" + reflect "reflect" + + types "github.com/ozontech/seq-ui/internal/app/types" + gomock "go.uber.org/mock/gomock" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder + isgomock struct{} +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// DeleteFavoriteQuery mocks base method. +func (m *MockService) DeleteFavoriteQuery(arg0 context.Context, arg1 types.DeleteFavoriteQueryRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteFavoriteQuery", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteFavoriteQuery indicates an expected call of DeleteFavoriteQuery. +func (mr *MockServiceMockRecorder) DeleteFavoriteQuery(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFavoriteQuery", reflect.TypeOf((*MockService)(nil).DeleteFavoriteQuery), arg0, arg1) +} + +// GetFavoriteQueries mocks base method. +func (m *MockService) GetFavoriteQueries(arg0 context.Context, arg1 types.GetFavoriteQueriesRequest) (types.FavoriteQueries, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFavoriteQueries", arg0, arg1) + ret0, _ := ret[0].(types.FavoriteQueries) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFavoriteQueries indicates an expected call of GetFavoriteQueries. +func (mr *MockServiceMockRecorder) GetFavoriteQueries(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFavoriteQueries", reflect.TypeOf((*MockService)(nil).GetFavoriteQueries), arg0, arg1) +} + +// GetOrCreateFavoriteQuery mocks base method. +func (m *MockService) GetOrCreateFavoriteQuery(arg0 context.Context, arg1 types.GetOrCreateFavoriteQueryRequest) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrCreateFavoriteQuery", arg0, arg1) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrCreateFavoriteQuery indicates an expected call of GetOrCreateFavoriteQuery. +func (mr *MockServiceMockRecorder) GetOrCreateFavoriteQuery(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrCreateFavoriteQuery", reflect.TypeOf((*MockService)(nil).GetOrCreateFavoriteQuery), arg0, arg1) +} + +// GetOrCreateUserProfile mocks base method. +func (m *MockService) GetOrCreateUserProfile(arg0 context.Context, arg1 types.GetOrCreateUserProfileRequest) (types.UserProfile, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrCreateUserProfile", arg0, arg1) + ret0, _ := ret[0].(types.UserProfile) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrCreateUserProfile indicates an expected call of GetOrCreateUserProfile. +func (mr *MockServiceMockRecorder) GetOrCreateUserProfile(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrCreateUserProfile", reflect.TypeOf((*MockService)(nil).GetOrCreateUserProfile), arg0, arg1) +} + +// UpdateUserProfile mocks base method. +func (m *MockService) UpdateUserProfile(arg0 context.Context, arg1 types.UpdateUserProfileRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserProfile", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateUserProfile indicates an expected call of UpdateUserProfile. +func (mr *MockServiceMockRecorder) UpdateUserProfile(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserProfile", reflect.TypeOf((*MockService)(nil).UpdateUserProfile), arg0, arg1) +} diff --git a/internal/pkg/service/userprofile/service.go b/internal/pkg/service/userprofile/service.go new file mode 100644 index 0000000..1f1b356 --- /dev/null +++ b/internal/pkg/service/userprofile/service.go @@ -0,0 +1,92 @@ +package userprofiles + +import ( + "context" + "time" + + "github.com/ozontech/seq-ui/internal/app/types" + "github.com/ozontech/seq-ui/internal/pkg/repository" + "github.com/ozontech/seq-ui/internal/pkg/service/profiles" +) + +type Service interface { + GetOrCreateUserProfile(context.Context, types.GetOrCreateUserProfileRequest) (types.UserProfile, error) + UpdateUserProfile(context.Context, types.UpdateUserProfileRequest) error + GetFavoriteQueries(context.Context, types.GetFavoriteQueriesRequest) (types.FavoriteQueries, error) + GetOrCreateFavoriteQuery(context.Context, types.GetOrCreateFavoriteQueryRequest) (int64, error) + DeleteFavoriteQuery(context.Context, types.DeleteFavoriteQueryRequest) error +} + +type service struct { + UserProfiles repository.UserProfiles + FavoriteQueries repository.FavoriteQueries +} + +func New(up repository.UserProfiles, fq repository.FavoriteQueries) Service { + return &service{ + UserProfiles: up, + FavoriteQueries: fq, + } +} + +func (s *service) GetOrCreateUserProfile(ctx context.Context, req types.GetOrCreateUserProfileRequest) (types.UserProfile, error) { + up, err := s.UserProfiles.GetOrCreate(ctx, req) + if err != nil { + return up, err + } + + profiles.SetID(req.UserName, up.ID) + + return up, nil +} + +func (s *service) UpdateUserProfile(ctx context.Context, req types.UpdateUserProfileRequest) error { + if req.IsEmpty() { + return types.ErrEmptyUpdateRequest + } + if req.Timezone != nil { + if _, err := time.LoadLocation(*req.Timezone); err != nil { + return types.NewErrInvalidRequestField("invalid timezone format") + } + } + + return s.UserProfiles.Update(ctx, req) +} + +func (s *service) GetFavoriteQueries(ctx context.Context, req types.GetFavoriteQueriesRequest) (types.FavoriteQueries, error) { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return nil, err + } + req.ProfileID = profileID + + return s.FavoriteQueries.GetAll(ctx, req) +} + +func (s *service) GetOrCreateFavoriteQuery(ctx context.Context, req types.GetOrCreateFavoriteQueryRequest) (int64, error) { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return 0, err + } + req.ProfileID = profileID + + if req.Query == "" { + return -1, types.NewErrInvalidRequestField("empty query") + } + + return s.FavoriteQueries.GetOrCreate(ctx, req) +} + +func (s *service) DeleteFavoriteQuery(ctx context.Context, req types.DeleteFavoriteQueryRequest) error { + profileID, err := profiles.GetIDFromContext(ctx) + if err != nil { + return err + } + req.ProfileID = profileID + + if req.ID <= 0 { + return types.NewErrInvalidRequestField("invalid id") + } + + return s.FavoriteQueries.Delete(ctx, req) +} From 0fdfca6dca5fcd94f0f0f30d2e4e1bdf5d5c88fb Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Mon, 22 Jun 2026 03:29:19 +0300 Subject: [PATCH 3/7] fix lint --- internal/api/userprofile/v1/http/favorite_queries_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/api/userprofile/v1/http/favorite_queries_test.go b/internal/api/userprofile/v1/http/favorite_queries_test.go index 38d6242..8497620 100644 --- a/internal/api/userprofile/v1/http/favorite_queries_test.go +++ b/internal/api/userprofile/v1/http/favorite_queries_test.go @@ -13,7 +13,6 @@ import ( ) func TestServeGetFavoriteQueries(t *testing.T) { - type mockArgs struct { req types.GetFavoriteQueriesRequest resp types.FavoriteQueries From 9d312dc40257d0461d5261d2db769d818c2ef78f Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Tue, 23 Jun 2026 01:57:22 +0300 Subject: [PATCH 4/7] fix --- cmd/seq-ui/main.go | 4 +- internal/api/dashboards/v1/dashboards.go | 2 +- internal/api/dashboards/v1/grpc/api.go | 10 +- .../api/dashboards/v1/grpc/create_test.go | 22 +-- .../api/dashboards/v1/grpc/delete_test.go | 10 +- .../api/dashboards/v1/grpc/get_all_test.go | 18 +-- .../dashboards/v1/grpc/get_by_uuid_test.go | 21 +-- .../api/dashboards/v1/grpc/get_my_test.go | 18 +-- .../api/dashboards/v1/grpc/search_test.go | 34 +++-- internal/api/dashboards/v1/grpc/test_data.go | 19 +-- .../api/dashboards/v1/grpc/update_test.go | 26 ++-- internal/api/dashboards/v1/http/api.go | 6 +- .../api/dashboards/v1/http/create_test.go | 8 +- .../api/dashboards/v1/http/delete_test.go | 4 +- .../api/dashboards/v1/http/get_all_test.go | 14 +- .../dashboards/v1/http/get_by_uuid_test.go | 4 +- .../api/dashboards/v1/http/get_my_test.go | 14 +- .../api/dashboards/v1/http/search_test.go | 25 ++-- internal/api/dashboards/v1/http/test_data.go | 12 +- .../api/dashboards/v1/http/update_test.go | 8 +- internal/api/massexport/v1/grpc/api.go | 4 +- .../api/massexport/v1/grpc/cancel_test.go | 68 --------- internal/api/massexport/v1/grpc/check_test.go | 80 ---------- .../api/massexport/v1/grpc/get_all_test.go | 86 ----------- .../api/massexport/v1/grpc/restore_test.go | 64 -------- internal/api/massexport/v1/grpc/start_test.go | 122 --------------- internal/api/massexport/v1/grpc/test_data.go | 28 ---- .../api/massexport/v1/http/cancel_test.go | 63 -------- internal/api/massexport/v1/http/check_test.go | 83 ----------- .../api/massexport/v1/http/get_all_test.go | 83 ----------- .../api/massexport/v1/http/restore_test.go | 63 -------- internal/api/massexport/v1/http/start_test.go | 118 --------------- internal/api/massexport/v1/http/test_data.go | 28 ---- .../api/seqapi/v1/grpc/aggregation_test.go | 28 ++-- .../v1/grpc/cancel_async_search_test.go | 23 ++- .../api/seqapi/v1/grpc/cluster_status_test.go | 18 +-- .../v1/grpc/delete_async_search_test.go | 23 ++- internal/api/seqapi/v1/grpc/events_test.go | 21 ++- .../v1/grpc/fetch_async_search_result_test.go | 55 +++---- internal/api/seqapi/v1/grpc/fields_test.go | 9 +- .../v1/grpc/get_async_searches_list_test.go | 59 ++++---- internal/api/seqapi/v1/grpc/histogram_test.go | 10 +- internal/api/seqapi/v1/grpc/limits_test.go | 2 +- .../api/seqapi/v1/grpc/logs_lifespan_test.go | 14 +- internal/api/seqapi/v1/grpc/search_test.go | 28 ++-- .../seqapi/v1/grpc/start_async_search_test.go | 20 ++- internal/api/seqapi/v1/grpc/test_data.go | 47 ++---- .../api/seqapi/v1/http/aggregation_test.go | 68 ++++----- .../api/seqapi/v1/http/aggregation_ts_test.go | 64 ++++---- .../v1/http/cancel_async_search_test.go | 18 +-- .../api/seqapi/v1/http/cluster_status_test.go | 10 +- .../v1/http/delete_async_search_test.go | 18 +-- internal/api/seqapi/v1/http/events_test.go | 29 +++- internal/api/seqapi/v1/http/export_test.go | 56 +++---- .../v1/http/fetch_async_search_result_test.go | 85 ++++++----- internal/api/seqapi/v1/http/fields_test.go | 10 +- .../v1/http/get_async_searches_list_test.go | 117 ++++++++------- internal/api/seqapi/v1/http/get_envs_test.go | 2 +- internal/api/seqapi/v1/http/histogram_test.go | 38 ++--- internal/api/seqapi/v1/http/limits_test.go | 2 +- .../api/seqapi/v1/http/logs_lifespan_test.go | 15 +- internal/api/seqapi/v1/http/search_test.go | 139 +++++++++--------- .../seqapi/v1/http/start_async_search_test.go | 36 +++-- internal/api/seqapi/v1/http/test_data.go | 57 ++----- internal/api/userprofile/v1/grpc/api.go | 10 +- .../v1/grpc/favorite_queries_test.go | 22 ++- internal/api/userprofile/v1/grpc/test_data.go | 14 +- .../userprofile/v1/grpc/user_profiles_test.go | 18 ++- internal/api/userprofile/v1/http/api.go | 2 +- .../v1/http/favorite_queries_test.go | 16 +- internal/api/userprofile/v1/http/test_data.go | 11 +- .../userprofile/v1/http/user_profiles_test.go | 18 ++- internal/api/userprofile/v1/userprofile.go | 2 +- internal/pkg/service/profiles/profiles.go | 40 +++-- internal/pkg/service/userprofile/service.go | 2 +- 75 files changed, 821 insertions(+), 1624 deletions(-) delete mode 100644 internal/api/massexport/v1/grpc/cancel_test.go delete mode 100644 internal/api/massexport/v1/grpc/check_test.go delete mode 100644 internal/api/massexport/v1/grpc/get_all_test.go delete mode 100644 internal/api/massexport/v1/grpc/restore_test.go delete mode 100644 internal/api/massexport/v1/grpc/start_test.go delete mode 100644 internal/api/massexport/v1/grpc/test_data.go delete mode 100644 internal/api/massexport/v1/http/cancel_test.go delete mode 100644 internal/api/massexport/v1/http/check_test.go delete mode 100644 internal/api/massexport/v1/http/get_all_test.go delete mode 100644 internal/api/massexport/v1/http/restore_test.go delete mode 100644 internal/api/massexport/v1/http/start_test.go delete mode 100644 internal/api/massexport/v1/http/test_data.go diff --git a/cmd/seq-ui/main.go b/cmd/seq-ui/main.go index faa4c21..bb3c7cc 100644 --- a/cmd/seq-ui/main.go +++ b/cmd/seq-ui/main.go @@ -30,13 +30,13 @@ import ( "github.com/ozontech/seq-ui/internal/pkg/repository" repositorych "github.com/ozontech/seq-ui/internal/pkg/repository_ch" asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches" - dashboards "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" + "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" "github.com/ozontech/seq-ui/internal/pkg/service/errorgroups" "github.com/ozontech/seq-ui/internal/pkg/service/massexport" "github.com/ozontech/seq-ui/internal/pkg/service/massexport/filestore" "github.com/ozontech/seq-ui/internal/pkg/service/massexport/sessionstore" "github.com/ozontech/seq-ui/internal/pkg/service/profiles" - userprofile "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" + "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" "github.com/ozontech/seq-ui/logger" "github.com/ozontech/seq-ui/tracing" ) diff --git a/internal/api/dashboards/v1/dashboards.go b/internal/api/dashboards/v1/dashboards.go index f245456..ec0031e 100644 --- a/internal/api/dashboards/v1/dashboards.go +++ b/internal/api/dashboards/v1/dashboards.go @@ -5,7 +5,7 @@ import ( grpc_api "github.com/ozontech/seq-ui/internal/api/dashboards/v1/grpc" http_api "github.com/ozontech/seq-ui/internal/api/dashboards/v1/http" - dashboards "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" + "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" ) type Dashboards struct { diff --git a/internal/api/dashboards/v1/grpc/api.go b/internal/api/dashboards/v1/grpc/api.go index 1a680b1..2422d0b 100644 --- a/internal/api/dashboards/v1/grpc/api.go +++ b/internal/api/dashboards/v1/grpc/api.go @@ -1,17 +1,17 @@ package grpc import ( - dashboardsservice "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" - "github.com/ozontech/seq-ui/pkg/dashboards/v1" + "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" + api "github.com/ozontech/seq-ui/pkg/dashboards/v1" ) type API struct { - dashboards.UnimplementedDashboardsServiceServer + api.UnimplementedDashboardsServiceServer - service dashboardsservice.Service + service dashboards.Service } -func New(svc dashboardsservice.Service) *API { +func New(svc dashboards.Service) *API { return &API{ service: svc, } diff --git a/internal/api/dashboards/v1/grpc/create_test.go b/internal/api/dashboards/v1/grpc/create_test.go index 4cb15ab..d143d57 100644 --- a/internal/api/dashboards/v1/grpc/create_test.go +++ b/internal/api/dashboards/v1/grpc/create_test.go @@ -32,32 +32,32 @@ func TestCreate(t *testing.T) { { name: "ok", req: &dashboards.CreateRequest{ - Name: dashboardName, - Meta: dashboardMeta, + Name: testDashboardName, + Meta: testDashboardMeta, }, want: &dashboards.CreateResponse{ - Uuid: dashboardUUID, + Uuid: testDashboardUUID, }, wantCode: codes.OK, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ - Name: dashboardName, - Meta: dashboardMeta, + Name: testDashboardName, + Meta: testDashboardMeta, }, - resp: dashboardUUID, + resp: testDashboardUUID, }, }, { name: "err_svc", req: &dashboards.CreateRequest{ - Name: dashboardName, - Meta: dashboardMeta, + Name: testDashboardName, + Meta: testDashboardMeta, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.CreateDashboardRequest{ - Name: dashboardName, - Meta: dashboardMeta, + Name: testDashboardName, + Meta: testDashboardMeta, }, err: errSomethingWrong, }, @@ -68,7 +68,7 @@ func TestCreate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/grpc/delete_test.go b/internal/api/dashboards/v1/grpc/delete_test.go index a9bd68a..8cd9a9c 100644 --- a/internal/api/dashboards/v1/grpc/delete_test.go +++ b/internal/api/dashboards/v1/grpc/delete_test.go @@ -31,25 +31,25 @@ func TestDelete(t *testing.T) { { name: "ok", req: &dashboards.DeleteRequest{ - Uuid: dashboardUUID, + Uuid: testDashboardUUID, }, want: &dashboards.DeleteResponse{}, wantCode: codes.OK, mockArgs: &mockArgs{ req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, + UUID: testDashboardUUID, }, }, }, { name: "err_svc", req: &dashboards.DeleteRequest{ - Uuid: dashboardUUID, + Uuid: testDashboardUUID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.DeleteDashboardRequest{ - UUID: dashboardUUID, + UUID: testDashboardUUID, }, err: errSomethingWrong, }, @@ -60,7 +60,7 @@ func TestDelete(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/grpc/get_all_test.go b/internal/api/dashboards/v1/grpc/get_all_test.go index b9a24ac..7878255 100644 --- a/internal/api/dashboards/v1/grpc/get_all_test.go +++ b/internal/api/dashboards/v1/grpc/get_all_test.go @@ -32,8 +32,8 @@ func TestGetAll(t *testing.T) { { name: "ok", req: &dashboards.GetAllRequest{ - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), }, want: &dashboards.GetAllResponse{ Dashboards: []*dashboards.GetAllResponse_Dashboard{ @@ -44,8 +44,8 @@ func TestGetAll(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, resp: types.DashboardInfosWithOwner{ { @@ -68,14 +68,14 @@ func TestGetAll(t *testing.T) { { name: "err_svc", req: &dashboards.GetAllRequest{ - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, err: errSomethingWrong, }, @@ -86,7 +86,7 @@ func TestGetAll(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/grpc/get_by_uuid_test.go b/internal/api/dashboards/v1/grpc/get_by_uuid_test.go index ac0c639..585b755 100644 --- a/internal/api/dashboards/v1/grpc/get_by_uuid_test.go +++ b/internal/api/dashboards/v1/grpc/get_by_uuid_test.go @@ -14,6 +14,9 @@ import ( ) func TestGetByUUID(t *testing.T) { + var ( + dashboardOwner = "owner" + ) type mockArgs struct { uuid string resp types.Dashboard @@ -32,19 +35,19 @@ func TestGetByUUID(t *testing.T) { { name: "ok", req: &dashboards.GetByUUIDRequest{ - Uuid: dashboardUUID, + Uuid: testDashboardUUID, }, want: &dashboards.GetByUUIDResponse{ - Name: dashboardName, - Meta: dashboardMeta, + Name: testDashboardName, + Meta: testDashboardMeta, OwnerName: dashboardOwner, }, wantCode: codes.OK, mockArgs: &mockArgs{ - uuid: dashboardUUID, + uuid: testDashboardUUID, resp: types.Dashboard{ - Name: dashboardName, - Meta: dashboardMeta, + Name: testDashboardName, + Meta: testDashboardMeta, OwnerName: dashboardOwner, }, }, @@ -52,11 +55,11 @@ func TestGetByUUID(t *testing.T) { { name: "err_svc", req: &dashboards.GetByUUIDRequest{ - Uuid: dashboardUUID, + Uuid: testDashboardUUID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ - uuid: dashboardUUID, + uuid: testDashboardUUID, err: errSomethingWrong, }, }, @@ -66,7 +69,7 @@ func TestGetByUUID(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/grpc/get_my_test.go b/internal/api/dashboards/v1/grpc/get_my_test.go index bab0f8b..cffaf3d 100644 --- a/internal/api/dashboards/v1/grpc/get_my_test.go +++ b/internal/api/dashboards/v1/grpc/get_my_test.go @@ -32,8 +32,8 @@ func TestGetMy(t *testing.T) { { name: "ok", req: &dashboards.GetMyRequest{ - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), }, want: &dashboards.GetMyResponse{ Dashboards: []*dashboards.GetMyResponse_Dashboard{ @@ -44,8 +44,8 @@ func TestGetMy(t *testing.T) { wantCode: codes.OK, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, resp: types.DashboardInfos{ {UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, @@ -56,14 +56,14 @@ func TestGetMy(t *testing.T) { { name: "err_svc", req: &dashboards.GetMyRequest{ - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, err: errSomethingWrong, }, @@ -74,7 +74,7 @@ func TestGetMy(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/grpc/search_test.go b/internal/api/dashboards/v1/grpc/search_test.go index 95d1c3d..2a9f032 100644 --- a/internal/api/dashboards/v1/grpc/search_test.go +++ b/internal/api/dashboards/v1/grpc/search_test.go @@ -14,6 +14,10 @@ import ( ) func TestSearch(t *testing.T) { + var ( + userName = "unnamed" + ) + type mockArgs struct { req types.SearchDashboardsRequest resp types.DashboardInfosWithOwner @@ -33,8 +37,8 @@ func TestSearch(t *testing.T) { name: "ok", req: &dashboards.SearchRequest{ Query: "test", - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), }, want: &dashboards.SearchResponse{ Dashboards: []*dashboards.SearchResponse_Dashboard{ @@ -46,8 +50,8 @@ func TestSearch(t *testing.T) { mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: "test", - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, resp: types.DashboardInfosWithOwner{ { @@ -71,8 +75,8 @@ func TestSearch(t *testing.T) { name: "ok_with_filter", req: &dashboards.SearchRequest{ Query: "test", - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), Filter: &dashboards.SearchRequest_Filter{ OwnerName: &userName, }, @@ -86,9 +90,11 @@ func TestSearch(t *testing.T) { mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: "test", - Limit: limit, - Offset: offset, - Filter: filter, + Limit: testLimit, + Offset: testOffset, + Filter: &types.SearchDashboardsFilter{ + OwnerName: &userName, + }, }, resp: types.DashboardInfosWithOwner{ { @@ -105,15 +111,15 @@ func TestSearch(t *testing.T) { name: "err_svc", req: &dashboards.SearchRequest{ Query: "test", - Limit: int32(limit), - Offset: int32(offset), + Limit: int32(testLimit), + Offset: int32(testOffset), }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: "test", - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, err: errSomethingWrong, }, @@ -124,7 +130,7 @@ func TestSearch(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/grpc/test_data.go b/internal/api/dashboards/v1/grpc/test_data.go index e59d9b1..111c97c 100644 --- a/internal/api/dashboards/v1/grpc/test_data.go +++ b/internal/api/dashboards/v1/grpc/test_data.go @@ -6,25 +6,20 @@ import ( "go.uber.org/mock/gomock" - "github.com/ozontech/seq-ui/internal/app/types" mock "github.com/ozontech/seq-ui/internal/pkg/service/dashboards/mock" ) +// Shared test data. var ( errSomethingWrong = errors.New("something happened wrong") - userName = "unnamed" - dashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName = "my_dashboard" - dashboardMeta = "my_meta" - dashboardOwner = "owner" - limit = 2 - offset = 0 - filter = &types.SearchDashboardsFilter{ - OwnerName: &userName, - } + testDashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" + testDashboardName = "my_dashboard" + testDashboardMeta = "my_meta" + testLimit = 2 + testOffset = 0 ) -func setupAPI(t *testing.T) (*API, *mock.MockService) { +func setupTestAPI(t *testing.T) (*API, *mock.MockService) { ctrl := gomock.NewController(t) mockedSvc := mock.NewMockService(ctrl) return New(mockedSvc), mockedSvc diff --git a/internal/api/dashboards/v1/grpc/update_test.go b/internal/api/dashboards/v1/grpc/update_test.go index d0151a8..578b5ed 100644 --- a/internal/api/dashboards/v1/grpc/update_test.go +++ b/internal/api/dashboards/v1/grpc/update_test.go @@ -31,33 +31,33 @@ func TestUpdate(t *testing.T) { { name: "ok", req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + Uuid: testDashboardUUID, + Name: &testDashboardName, + Meta: &testDashboardMeta, }, want: &dashboards.UpdateResponse{}, wantCode: codes.OK, mockArgs: &mockArgs{ req: types.UpdateDashboardRequest{ - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + UUID: testDashboardUUID, + Name: &testDashboardName, + Meta: &testDashboardMeta, }, }, }, { name: "err_svc", req: &dashboards.UpdateRequest{ - Uuid: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + Uuid: testDashboardUUID, + Name: &testDashboardName, + Meta: &testDashboardMeta, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: types.UpdateDashboardRequest{ - UUID: dashboardUUID, - Name: &dashboardName, - Meta: &dashboardMeta, + UUID: testDashboardUUID, + Name: &testDashboardName, + Meta: &testDashboardMeta, }, err: errSomethingWrong, }, @@ -68,7 +68,7 @@ func TestUpdate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/http/api.go b/internal/api/dashboards/v1/http/api.go index ed506af..da629d0 100644 --- a/internal/api/dashboards/v1/http/api.go +++ b/internal/api/dashboards/v1/http/api.go @@ -4,14 +4,14 @@ import ( "github.com/go-chi/chi/v5" "github.com/ozontech/seq-ui/internal/app/types" - dashboardsservice "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" + "github.com/ozontech/seq-ui/internal/pkg/service/dashboards" ) type API struct { - service dashboardsservice.Service + service dashboards.Service } -func New(svc dashboardsservice.Service) *API { +func New(svc dashboards.Service) *API { return &API{ service: svc, } diff --git a/internal/api/dashboards/v1/http/create_test.go b/internal/api/dashboards/v1/http/create_test.go index 29be020..ae791f3 100644 --- a/internal/api/dashboards/v1/http/create_test.go +++ b/internal/api/dashboards/v1/http/create_test.go @@ -11,6 +11,12 @@ import ( ) func TestServeCreate(t *testing.T) { + var ( + dashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" + dashboardMeta = "my_meta" + dashboardName = "my_dashboard" + ) + type mockArgs struct { req types.CreateDashboardRequest resp string @@ -56,7 +62,7 @@ func TestServeCreate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/http/delete_test.go b/internal/api/dashboards/v1/http/delete_test.go index d7308ab..36b4df1 100644 --- a/internal/api/dashboards/v1/http/delete_test.go +++ b/internal/api/dashboards/v1/http/delete_test.go @@ -12,6 +12,8 @@ import ( ) func TestServeDelete(t *testing.T) { + dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" + type mockArgs struct { req types.DeleteDashboardRequest err error @@ -47,7 +49,7 @@ func TestServeDelete(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/http/get_all_test.go b/internal/api/dashboards/v1/http/get_all_test.go index 9f62aa5..94c3b6a 100644 --- a/internal/api/dashboards/v1/http/get_all_test.go +++ b/internal/api/dashboards/v1/http/get_all_test.go @@ -28,7 +28,7 @@ func TestServeGetAll(t *testing.T) { }{ { name: "ok", - req: getAllRequest{Limit: limit, Offset: offset}, + req: getAllRequest{Limit: testLimit, Offset: testOffset}, want: getAllResponse{ Dashboards: infosWithOwner{ {info: info{UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, OwnerName: "user1"}, @@ -37,8 +37,8 @@ func TestServeGetAll(t *testing.T) { }, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, resp: types.DashboardInfosWithOwner{ { @@ -60,12 +60,12 @@ func TestServeGetAll(t *testing.T) { }, { name: "err_svc", - req: getAllRequest{Limit: limit, Offset: offset}, + req: getAllRequest{Limit: testLimit, Offset: testOffset}, wantErr: true, mockArgs: &mockArgs{ req: types.GetAllDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, err: errSomethingWrong, }, @@ -76,7 +76,7 @@ func TestServeGetAll(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/http/get_by_uuid_test.go b/internal/api/dashboards/v1/http/get_by_uuid_test.go index da2f63e..f3844fe 100644 --- a/internal/api/dashboards/v1/http/get_by_uuid_test.go +++ b/internal/api/dashboards/v1/http/get_by_uuid_test.go @@ -12,6 +12,8 @@ import ( ) func TestServeGetByUUID(t *testing.T) { + dashboardUUID := "064dc707-02b8-7000-8201-02a7f396738a" + type mockArgs struct { uuid string resp types.Dashboard @@ -56,7 +58,7 @@ func TestServeGetByUUID(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/http/get_my_test.go b/internal/api/dashboards/v1/http/get_my_test.go index b25ef12..e3a0a44 100644 --- a/internal/api/dashboards/v1/http/get_my_test.go +++ b/internal/api/dashboards/v1/http/get_my_test.go @@ -28,7 +28,7 @@ func TestServeGetMy(t *testing.T) { }{ { name: "ok", - req: getMyRequest{Limit: limit, Offset: offset}, + req: getMyRequest{Limit: testLimit, Offset: testOffset}, want: getMyResponse{ Dashboards: infos{ {UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, @@ -37,8 +37,8 @@ func TestServeGetMy(t *testing.T) { }, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, resp: types.DashboardInfos{ {UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "dashboard1"}, @@ -48,12 +48,12 @@ func TestServeGetMy(t *testing.T) { }, { name: "err_svc", - req: getMyRequest{Limit: limit, Offset: offset}, + req: getMyRequest{Limit: testLimit, Offset: testOffset}, wantErr: true, mockArgs: &mockArgs{ req: types.GetUserDashboardsRequest{ - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, err: errSomethingWrong, }, @@ -64,7 +64,7 @@ func TestServeGetMy(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedRepo := setupAPI(t) + api, mockedRepo := setupTestAPI(t) if tt.mockArgs != nil { mockedRepo.EXPECT(). diff --git a/internal/api/dashboards/v1/http/search_test.go b/internal/api/dashboards/v1/http/search_test.go index 630b303..d972192 100644 --- a/internal/api/dashboards/v1/http/search_test.go +++ b/internal/api/dashboards/v1/http/search_test.go @@ -11,6 +11,9 @@ import ( ) func TestServeSearch(t *testing.T) { + userName := "unnamed" + query := "test-query" + type mockArgs struct { req types.SearchDashboardsRequest resp types.DashboardInfosWithOwner @@ -28,7 +31,7 @@ func TestServeSearch(t *testing.T) { }{ { name: "ok", - req: searchRequest{Query: query, Limit: limit, Offset: offset}, + req: searchRequest{Query: query, Limit: testLimit, Offset: testOffset}, want: searchResponse{ Dashboards: infosWithOwner{ {info: info{UUID: "064dc707-02b8-7000-8201-02a7f396738a", Name: "my test dashboard"}, OwnerName: "user1"}, @@ -38,8 +41,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: query, - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, resp: types.DashboardInfosWithOwner{ { @@ -63,8 +66,8 @@ func TestServeSearch(t *testing.T) { name: "ok_filter", req: searchRequest{ Query: query, - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, Filter: &searchFilter{OwnerName: &userName}, }, want: searchResponse{ @@ -75,8 +78,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: query, - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, Filter: &types.SearchDashboardsFilter{ OwnerName: &userName, }, @@ -94,13 +97,13 @@ func TestServeSearch(t *testing.T) { }, { name: "err_svc", - req: searchRequest{Query: query, Limit: limit, Offset: offset}, + req: searchRequest{Query: query, Limit: testLimit, Offset: testOffset}, wantErr: true, mockArgs: &mockArgs{ req: types.SearchDashboardsRequest{ Query: query, - Limit: limit, - Offset: offset, + Limit: testLimit, + Offset: testOffset, }, err: errSomethingWrong, }, @@ -111,7 +114,7 @@ func TestServeSearch(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/dashboards/v1/http/test_data.go b/internal/api/dashboards/v1/http/test_data.go index 6f3861c..dbdc1f0 100644 --- a/internal/api/dashboards/v1/http/test_data.go +++ b/internal/api/dashboards/v1/http/test_data.go @@ -12,18 +12,14 @@ import ( mock "github.com/ozontech/seq-ui/internal/pkg/service/dashboards/mock" ) +// Shared test data. var ( errSomethingWrong = errors.New("something happened wrong") - userName = "unnamed" - dashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" - dashboardName = "my_dashboard" - dashboardMeta = "my_meta" - query = "test-query" - limit = 2 - offset = 0 + testLimit = 2 + testOffset = 0 ) -func setupAPI(t *testing.T) (*API, *mock.MockService) { +func setupTestAPI(t *testing.T) (*API, *mock.MockService) { ctrl := gomock.NewController(t) mockedSvc := mock.NewMockService(ctrl) return New(mockedSvc), mockedSvc diff --git a/internal/api/dashboards/v1/http/update_test.go b/internal/api/dashboards/v1/http/update_test.go index 96ec57b..bd1226e 100644 --- a/internal/api/dashboards/v1/http/update_test.go +++ b/internal/api/dashboards/v1/http/update_test.go @@ -12,6 +12,12 @@ import ( ) func TestServeUpdate(t *testing.T) { + var ( + dashboardUUID = "064dc707-02b8-7000-8201-02a7f396738a" + dashboardMeta = "my_meta" + dashboardName = "my_dashboard" + ) + type mockArgs struct { req types.UpdateDashboardRequest err error @@ -55,7 +61,7 @@ func TestServeUpdate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT().UpdateDashboard(gomock.Any(), tt.mockArgs.req). diff --git a/internal/api/massexport/v1/grpc/api.go b/internal/api/massexport/v1/grpc/api.go index fc424cf..bb0b2c5 100644 --- a/internal/api/massexport/v1/grpc/api.go +++ b/internal/api/massexport/v1/grpc/api.go @@ -2,11 +2,11 @@ package grpc import ( "github.com/ozontech/seq-ui/internal/pkg/service/massexport" - massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" + api "github.com/ozontech/seq-ui/pkg/massexport/v1" ) type API struct { - massexport_v1.UnimplementedMassExportServiceServer + api.UnimplementedMassExportServiceServer exporter massexport.Service } diff --git a/internal/api/massexport/v1/grpc/cancel_test.go b/internal/api/massexport/v1/grpc/cancel_test.go deleted file mode 100644 index 42e61e5..0000000 --- a/internal/api/massexport/v1/grpc/cancel_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package grpc - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" -) - -func TestCancel(t *testing.T) { - type mockArgs struct { - err error - } - - tests := []struct { - name string - - req *massexport_v1.CancelRequest - want *massexport_v1.CancelResponse - wantCode codes.Code - - mockArgs *mockArgs - }{ - { - name: "ok", - req: &massexport_v1.CancelRequest{SessionId: sessionID}, - want: &massexport_v1.CancelResponse{}, - mockArgs: &mockArgs{}, - }, - { - name: "svc_err", - req: &massexport_v1.CancelRequest{SessionId: sessionID}, - wantCode: codes.Internal, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - CancelExport(gomock.Any(), tt.req.GetSessionId()). - Return(tt.mockArgs.err). - Times(1) - } - - got, err := api.Cancel(context.Background(), tt.req) - - require.Equal(t, tt.wantCode, status.Code(err)) - if tt.wantCode != codes.OK { - return - } - - require.Equal(t, tt.want, got) - }) - } -} diff --git a/internal/api/massexport/v1/grpc/check_test.go b/internal/api/massexport/v1/grpc/check_test.go deleted file mode 100644 index e5cabfe..0000000 --- a/internal/api/massexport/v1/grpc/check_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package grpc - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/ozontech/seq-ui/internal/app/types" - massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" -) - -func TestCheck(t *testing.T) { - type mockArgs struct { - resp types.ExportInfo - err error - } - - tests := []struct { - name string - - req *massexport_v1.CheckRequest - want *massexport_v1.CheckResponse - wantCode codes.Code - - mockArgs *mockArgs - }{ - { - name: "ok", - req: &massexport_v1.CheckRequest{SessionId: sessionID}, - want: convertExportInfo(types.ExportInfo{ - ID: sessionID, - UserID: userID, - Status: types.ExportStatusFinish, - }), - mockArgs: &mockArgs{ - resp: types.ExportInfo{ - ID: sessionID, - UserID: userID, - Status: types.ExportStatusFinish, - }, - }, - }, - { - name: "err_svc", - req: &massexport_v1.CheckRequest{SessionId: sessionID}, - wantCode: codes.Internal, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - CheckExport(gomock.Any(), tt.req.GetSessionId()). - Return(tt.mockArgs.resp, tt.mockArgs.err). - Times(1) - } - - got, err := api.Check(context.Background(), tt.req) - - require.Equal(t, tt.wantCode, status.Code(err)) - if tt.wantCode != codes.OK { - return - } - - require.Equal(t, tt.want, got) - }) - } -} diff --git a/internal/api/massexport/v1/grpc/get_all_test.go b/internal/api/massexport/v1/grpc/get_all_test.go deleted file mode 100644 index 0c7ac6e..0000000 --- a/internal/api/massexport/v1/grpc/get_all_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package grpc - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/ozontech/seq-ui/internal/app/types" - massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" -) - -func TestGetAll(t *testing.T) { - type mockArgs struct { - resp []types.ExportInfo - err error - } - - tests := []struct { - name string - - req *massexport_v1.GetAllRequest - want *massexport_v1.GetAllResponse - wantCode codes.Code - - mockArgs *mockArgs - }{ - { - name: "ok", - req: &massexport_v1.GetAllRequest{}, - want: &massexport_v1.GetAllResponse{ - Exports: []*massexport_v1.CheckResponse{ - convertExportInfo(types.ExportInfo{ - ID: sessionID, - UserID: userID, - Status: types.ExportStatusFinish, - }), - }, - }, - mockArgs: &mockArgs{ - resp: []types.ExportInfo{ - { - ID: sessionID, - UserID: userID, - Status: types.ExportStatusFinish, - }, - }, - }, - }, - { - name: "err_svc", - req: &massexport_v1.GetAllRequest{}, - wantCode: codes.Internal, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - GetAll(gomock.Any()). - Return(tt.mockArgs.resp, tt.mockArgs.err). - Times(1) - } - - got, err := api.GetAll(context.Background(), tt.req) - - require.Equal(t, tt.wantCode, status.Code(err)) - if tt.wantCode != codes.OK { - return - } - - require.Equal(t, tt.want, got) - }) - } -} diff --git a/internal/api/massexport/v1/grpc/restore_test.go b/internal/api/massexport/v1/grpc/restore_test.go deleted file mode 100644 index 594d78b..0000000 --- a/internal/api/massexport/v1/grpc/restore_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package grpc - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" -) - -func TestRestore(t *testing.T) { - type mockArgs struct { - err error - } - - tests := []struct { - name string - - req *massexport_v1.RestoreRequest - wantCode codes.Code - - mockArgs *mockArgs - }{ - { - name: "ok", - req: &massexport_v1.RestoreRequest{SessionId: sessionID}, - mockArgs: &mockArgs{}, - }, - { - name: "err_svc", - req: &massexport_v1.RestoreRequest{SessionId: sessionID}, - wantCode: codes.Internal, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - RestoreExport(gomock.Any(), tt.req.GetSessionId()). - Return(tt.mockArgs.err). - Times(1) - } - - _, err := api.Restore(context.Background(), tt.req) - - require.Equal(t, tt.wantCode, status.Code(err)) - if tt.wantCode != codes.OK { - return - } - }) - } -} diff --git a/internal/api/massexport/v1/grpc/start_test.go b/internal/api/massexport/v1/grpc/start_test.go deleted file mode 100644 index b4e6346..0000000 --- a/internal/api/massexport/v1/grpc/start_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package grpc - -import ( - "context" - "testing" - "time" - - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/types/known/timestamppb" - - "github.com/ozontech/seq-ui/internal/app/types" - massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" -) - -func TestStart(t *testing.T) { - type mockArgs struct { - resp types.StartExportResponse - err error - } - - tests := []struct { - name string - - req *massexport_v1.StartRequest - want *massexport_v1.StartResponse - wantCode codes.Code - - mockArgs *mockArgs - }{ - { - name: "ok", - req: &massexport_v1.StartRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), - Window: testWindow, - Name: testName, - }, - want: &massexport_v1.StartResponse{ - SessionId: sessionID, - }, - mockArgs: &mockArgs{ - resp: types.StartExportResponse{ - SessionID: sessionID, - }, - }, - }, - { - name: "err_empty_name", - req: &massexport_v1.StartRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), - Window: testWindow, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_invalid_window", - req: &massexport_v1.StartRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), - Window: "invalid", - Name: testName, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_window_larger_than_interval", - req: &massexport_v1.StartRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(from.Add(5 * time.Second)), - Window: testWindow, - Name: testName, - }, - wantCode: codes.InvalidArgument, - }, - { - name: "err_svc", - req: &massexport_v1.StartRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), - Window: testWindow, - Name: testName, - }, - wantCode: codes.Internal, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - StartExport(gomock.Any(), gomock.Any()). - Return(tt.mockArgs.resp, tt.mockArgs.err). - Times(1) - } - - got, err := api.Start(context.Background(), tt.req) - - require.Equal(t, tt.wantCode, status.Code(err)) - if tt.wantCode != codes.OK { - return - } - - require.Equal(t, tt.want, got) - }) - } -} diff --git a/internal/api/massexport/v1/grpc/test_data.go b/internal/api/massexport/v1/grpc/test_data.go deleted file mode 100644 index d319e91..0000000 --- a/internal/api/massexport/v1/grpc/test_data.go +++ /dev/null @@ -1,28 +0,0 @@ -package grpc - -import ( - "errors" - "testing" - "time" - - "go.uber.org/mock/gomock" - - mock_massexport "github.com/ozontech/seq-ui/internal/pkg/service/massexport/mock" -) - -var ( - errSomethingWrong = errors.New("something happened wrong") - query = "message:error" - testName = "test-export" - testWindow = "10s" - sessionID = "test-session-id" - userID = "test-user" - from = time.Now() - to = from.Add(10 * time.Minute) -) - -func setupAPI(t *testing.T) (*API, *mock_massexport.MockService) { - ctrl := gomock.NewController(t) - svcMock := mock_massexport.NewMockService(ctrl) - return New(svcMock), svcMock -} diff --git a/internal/api/massexport/v1/http/cancel_test.go b/internal/api/massexport/v1/http/cancel_test.go deleted file mode 100644 index 43b51e2..0000000 --- a/internal/api/massexport/v1/http/cancel_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package http - -import ( - "net/http" - "testing" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/httputil" -) - -func TestServeCancel(t *testing.T) { - type mockArgs struct { - err error - } - - tests := []struct { - name string - - req cancelRequest - wantErr bool - - mockArgs *mockArgs - }{ - { - name: "ok", - req: cancelRequest{SessionID: sessionID}, - mockArgs: &mockArgs{}, - }, - { - name: "err_svc", - req: cancelRequest{SessionID: sessionID}, - wantErr: true, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - CancelExport(gomock.Any(), tt.req.SessionID). - Return(tt.mockArgs.err). - Times(1) - } - - httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[cancelRequest, struct{}]{ - Method: http.MethodPost, - Target: "/massexport/v1/cancel", - Req: tt.req, - Handler: api.serveCancel, - WantErr: tt.wantErr, - NoResp: true, - }) - }) - } -} diff --git a/internal/api/massexport/v1/http/check_test.go b/internal/api/massexport/v1/http/check_test.go deleted file mode 100644 index 7450c9d..0000000 --- a/internal/api/massexport/v1/http/check_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package http - -import ( - "net/http" - "testing" - "time" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/httputil" - "github.com/ozontech/seq-ui/internal/app/types" -) - -func TestServeCheck(t *testing.T) { - type mockArgs struct { - resp types.ExportInfo - err error - } - - tests := []struct { - name string - - req checkRequest - want checkResponse - wantErr bool - - mockArgs *mockArgs - }{ - { - name: "ok", - req: checkRequest{SessionID: sessionID}, - mockArgs: &mockArgs{ - resp: types.ExportInfo{ - ID: sessionID, - UserID: userID, - Status: types.ExportStatusFinish, - StartedAt: from, - FinishedAt: to, - }, - }, - want: checkResponse{ - ID: sessionID, - UserID: userID, - Status: exportStatusFinish, - StartedAt: from, - FinishedAt: to, - Duration: (10 * time.Minute).String(), - }, - }, - { - name: "err_svc", - req: checkRequest{SessionID: sessionID}, - wantErr: true, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - CheckExport(gomock.Any(), tt.req.SessionID). - Return(tt.mockArgs.resp, tt.mockArgs.err). - Times(1) - } - - httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[checkRequest, checkResponse]{ - Method: http.MethodPost, - Target: "/massexport/v1/check", - Req: tt.req, - Handler: api.serveCheck, - Want: tt.want, - WantErr: tt.wantErr, - }) - }) - } -} diff --git a/internal/api/massexport/v1/http/get_all_test.go b/internal/api/massexport/v1/http/get_all_test.go deleted file mode 100644 index 0880334..0000000 --- a/internal/api/massexport/v1/http/get_all_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package http - -import ( - "net/http" - "testing" - "time" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/httputil" - "github.com/ozontech/seq-ui/internal/app/types" -) - -func TestServeGetAll(t *testing.T) { - type mockArgs struct { - resp []types.ExportInfo - err error - } - - tests := []struct { - name string - - want getAllResponse - wantErr bool - - mockArgs mockArgs - }{ - { - name: "ok", - mockArgs: mockArgs{ - resp: []types.ExportInfo{ - { - ID: sessionID, - UserID: userID, - Status: types.ExportStatusFinish, - StartedAt: from, - FinishedAt: to, - }, - }, - }, - want: getAllResponse{ - Exports: []checkResponse{ - { - ID: sessionID, - UserID: userID, - Status: exportStatusFinish, - StartedAt: from, - FinishedAt: to, - Duration: (10 * time.Minute).String(), - }, - }, - }, - }, - { - name: "err_svc", - wantErr: true, - mockArgs: mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - svcMock.EXPECT(). - GetAll(gomock.Any()). - Return(tt.mockArgs.resp, tt.mockArgs.err). - Times(1) - - httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getAllResponse]{ - Method: http.MethodGet, - Target: "/massexport/v1/jobs", - Handler: api.serveJobs, - Want: tt.want, - WantErr: tt.wantErr, - }) - }) - } -} diff --git a/internal/api/massexport/v1/http/restore_test.go b/internal/api/massexport/v1/http/restore_test.go deleted file mode 100644 index 016ec53..0000000 --- a/internal/api/massexport/v1/http/restore_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package http - -import ( - "net/http" - "testing" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/httputil" -) - -func TestServeRestore(t *testing.T) { - type mockArgs struct { - err error - } - - tests := []struct { - name string - - req restoreRequest - wantErr bool - - mockArgs *mockArgs - }{ - { - name: "ok", - req: restoreRequest{SessionID: sessionID}, - mockArgs: &mockArgs{}, - }, - { - name: "err_svc", - req: restoreRequest{SessionID: sessionID}, - wantErr: true, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - RestoreExport(gomock.Any(), tt.req.SessionID). - Return(tt.mockArgs.err). - Times(1) - } - - httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[restoreRequest, struct{}]{ - Method: http.MethodPost, - Target: "/massexport/v1/restore", - Req: tt.req, - Handler: api.serveRestore, - WantErr: tt.wantErr, - NoResp: true, - }) - }) - } -} diff --git a/internal/api/massexport/v1/http/start_test.go b/internal/api/massexport/v1/http/start_test.go deleted file mode 100644 index 7467a10..0000000 --- a/internal/api/massexport/v1/http/start_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package http - -import ( - "net/http" - "testing" - "time" - - "go.uber.org/mock/gomock" - - "github.com/ozontech/seq-ui/internal/api/httputil" - "github.com/ozontech/seq-ui/internal/app/types" -) - -func TestServeStart(t *testing.T) { - type mockArgs struct { - resp types.StartExportResponse - err error - } - - tests := []struct { - name string - - req startRequest - want startResponse - wantErr bool - - mockArgs *mockArgs - }{ - { - name: "ok", - req: startRequest{ - Query: query, - From: from, - To: to, - Window: window, - Name: testName, - }, - want: startResponse{ - SessionID: sessionID, - }, - mockArgs: &mockArgs{ - resp: types.StartExportResponse{ - SessionID: sessionID, - }, - }, - }, - { - name: "err_empty_name", - req: startRequest{ - Query: query, - From: from, - To: to, - Window: window, - }, - wantErr: true, - }, - { - name: "err_invalid_window", - req: startRequest{ - Query: query, - From: from, - To: to, - Window: "invalid", - Name: testName, - }, - wantErr: true, - }, - { - name: "err_window_larger_than_interval", - req: startRequest{ - Query: query, - From: from, - To: from.Add(5 * time.Second), - Window: window, - Name: testName, - }, - wantErr: true, - }, - { - name: "err_svc", - req: startRequest{ - Query: query, - From: from, - To: to, - Window: window, - Name: testName, - }, - wantErr: true, - mockArgs: &mockArgs{ - err: errSomethingWrong, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - api, svcMock := setupAPI(t) - - if tt.mockArgs != nil { - svcMock.EXPECT(). - StartExport(gomock.Any(), gomock.Any()). - Return(tt.mockArgs.resp, tt.mockArgs.err). - Times(1) - } - - httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[startRequest, startResponse]{ - Method: http.MethodPost, - Target: "/massexport/v1/start", - Req: tt.req, - Handler: api.serveStart, - Want: tt.want, - WantErr: tt.wantErr, - }) - }) - } -} diff --git a/internal/api/massexport/v1/http/test_data.go b/internal/api/massexport/v1/http/test_data.go deleted file mode 100644 index 74788a8..0000000 --- a/internal/api/massexport/v1/http/test_data.go +++ /dev/null @@ -1,28 +0,0 @@ -package http - -import ( - "errors" - "testing" - "time" - - "go.uber.org/mock/gomock" - - mock_massexport "github.com/ozontech/seq-ui/internal/pkg/service/massexport/mock" -) - -var ( - errSomethingWrong = errors.New("something happened wrong") - query = "message:error" - testName = "test-export" - window = "10s" - sessionID = "test-session-id" - userID = "test-user" - from = time.Now() - to = from.Add(10 * time.Minute) -) - -func setupAPI(t *testing.T) (*API, *mock_massexport.MockService) { - ctrl := gomock.NewController(t) - svcMock := mock_massexport.NewMockService(ctrl) - return New(svcMock), svcMock -} diff --git a/internal/api/seqapi/v1/grpc/aggregation_test.go b/internal/api/seqapi/v1/grpc/aggregation_test.go index 1bfd43b..230604f 100644 --- a/internal/api/seqapi/v1/grpc/aggregation_test.go +++ b/internal/api/seqapi/v1/grpc/aggregation_test.go @@ -17,6 +17,9 @@ import ( ) func TestGetAggregation(t *testing.T) { + var ( + query = "message:error" + ) tests := []struct { name string @@ -32,8 +35,8 @@ func TestGetAggregation(t *testing.T) { name: "ok_multi_agg", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test1"}, {Field: "test2"}, @@ -71,8 +74,8 @@ func TestGetAggregation(t *testing.T) { name: "err_client", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test2"}, }, @@ -106,7 +109,7 @@ func TestGetAggregation(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) resp, err := api.GetAggregation(context.Background(), tt.req) if tt.apiErr { @@ -121,6 +124,11 @@ func TestGetAggregation(t *testing.T) { } func TestGetAggregationWithNormalization(t *testing.T) { + var ( + query = "message:error" + interval = "2s" + targetBucketRate = "3s" + ) tests := []struct { name string @@ -137,8 +145,8 @@ func TestGetAggregationWithNormalization(t *testing.T) { name: "ok_count", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, {Field: "test2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, @@ -178,8 +186,8 @@ func TestGetAggregationWithNormalization(t *testing.T) { name: "ok_normalize_count", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval, TargetBucketRate: &targetBucketRate}, {Field: "test2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval, TargetBucketRate: &targetBucketRate}, @@ -237,7 +245,7 @@ func TestGetAggregationWithNormalization(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) resp, err := api.GetAggregation(context.Background(), tt.req) if tt.apiErr { diff --git a/internal/api/seqapi/v1/grpc/cancel_async_search_test.go b/internal/api/seqapi/v1/grpc/cancel_async_search_test.go index 83e4013..293fb1b 100644 --- a/internal/api/seqapi/v1/grpc/cancel_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/cancel_async_search_test.go @@ -34,12 +34,12 @@ func TestCancelAsyncSearch(t *testing.T) { { name: "ok", req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, want: &seqapi.CancelAsyncSearchResponse{}, mockArgs: &mockArgs{ req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, resp: &seqapi.CancelAsyncSearchResponse{}, }, @@ -54,12 +54,12 @@ func TestCancelAsyncSearch(t *testing.T) { { name: "err_svc", req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, err: errSomethingWrong, }, @@ -70,21 +70,20 @@ func TestCancelAsyncSearch(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) + seqData := test.APITestData{} + seqData.Mocks.AsyncSearchesSvc = svcMock if tt.mockArgs != nil { - ctrl := gomock.NewController(t) - - svcMock := mock_asyncsearches.NewMockService(ctrl) svcMock.EXPECT(). CancelAsyncSearch(gomock.Any(), tt.mockArgs.req). Return(tt.mockArgs.resp, tt.mockArgs.err). Times(1) - - seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) got, err := api.CancelAsyncSearch(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) @@ -98,9 +97,9 @@ func TestCancelAsyncSearch(t *testing.T) { func TestCancelAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) - _, err := api.CancelAsyncSearch(context.Background(), &seqapi.CancelAsyncSearchRequest{}) + _, err := api.CancelAsyncSearch(context.Background(), &seqapi.CancelAsyncSearchRequest{SearchId: testSearchID}) require.Error(t, err) require.Equal(t, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()), err) } diff --git a/internal/api/seqapi/v1/grpc/cluster_status_test.go b/internal/api/seqapi/v1/grpc/cluster_status_test.go index 52dbe86..4c70c77 100644 --- a/internal/api/seqapi/v1/grpc/cluster_status_test.go +++ b/internal/api/seqapi/v1/grpc/cluster_status_test.go @@ -35,38 +35,38 @@ func TestStatus(t *testing.T) { name: "ok", want: &seqapi.StatusResponse{ NumberOfStores: 3, - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), Stores: []*seqapi.StoreStatus{ { Host: "host-0", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment)}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment)}, }, { Host: "host-1", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment.Add(1 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(1 * time.Hour))}, }, { Host: "host-2", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment.Add(2 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(2 * time.Hour))}, }, }, }, mockArgs: &mockArgs{ resp: &seqapi.StatusResponse{ NumberOfStores: 3, - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), Stores: []*seqapi.StoreStatus{ { Host: "host-0", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment)}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment)}, }, { Host: "host-1", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment.Add(1 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(1 * time.Hour))}, }, { Host: "host-2", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment.Add(2 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(2 * time.Hour))}, }, }, }, @@ -99,7 +99,7 @@ func TestStatus(t *testing.T) { }, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) got, err := api.Status(context.Background(), nil) diff --git a/internal/api/seqapi/v1/grpc/delete_async_search_test.go b/internal/api/seqapi/v1/grpc/delete_async_search_test.go index e1bac7c..70942eb 100644 --- a/internal/api/seqapi/v1/grpc/delete_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/delete_async_search_test.go @@ -34,12 +34,12 @@ func TestDeleteAsyncSearch(t *testing.T) { { name: "ok", req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, want: &seqapi.DeleteAsyncSearchResponse{}, mockArgs: &mockArgs{ req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, resp: &seqapi.DeleteAsyncSearchResponse{}, }, @@ -54,12 +54,12 @@ func TestDeleteAsyncSearch(t *testing.T) { { name: "err_svc", req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, wantCode: codes.Internal, mockArgs: &mockArgs{ req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, err: errSomethingWrong, }, @@ -70,21 +70,20 @@ func TestDeleteAsyncSearch(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) + seqData := test.APITestData{} + seqData.Mocks.AsyncSearchesSvc = svcMock if tt.mockArgs != nil { - ctrl := gomock.NewController(t) - - svcMock := mock_asyncsearches.NewMockService(ctrl) svcMock.EXPECT(). DeleteAsyncSearch(gomock.Any(), tt.mockArgs.req). Return(tt.mockArgs.resp, tt.mockArgs.err). Times(1) - - seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) got, err := api.DeleteAsyncSearch(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) @@ -98,9 +97,9 @@ func TestDeleteAsyncSearch(t *testing.T) { func TestServeDeleteAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) - _, err := api.DeleteAsyncSearch(context.Background(), &seqapi.DeleteAsyncSearchRequest{}) + _, err := api.DeleteAsyncSearch(context.Background(), &seqapi.DeleteAsyncSearchRequest{SearchId: testSearchID}) require.Error(t, err) require.Equal(t, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()), err) } diff --git a/internal/api/seqapi/v1/grpc/events_test.go b/internal/api/seqapi/v1/grpc/events_test.go index 34c99f4..17cd3f9 100644 --- a/internal/api/seqapi/v1/grpc/events_test.go +++ b/internal/api/seqapi/v1/grpc/events_test.go @@ -21,9 +21,15 @@ import ( ) func TestGetEvent(t *testing.T) { - event1 := test.MakeEvent(id1, 1, someMoment) + var ( + id1 = "test1" + id2 = "test2" + id3 = "test3" + id4 = "test4" + ) + event1 := test.MakeEvent(id1, 1, testSomeMoment) event1json, _ := proto.Marshal(event1) - event2 := test.MakeEvent(id2, 2, someMoment) + event2 := test.MakeEvent(id2, 2, testSomeMoment) event2json, _ := proto.Marshal(event2) event3 := &seqapi.Event{} event3json, _ := proto.Marshal(event3) @@ -128,7 +134,7 @@ func TestGetEvent(t *testing.T) { } } - s := setupAPI(seqData) + s := setupTestAPI(seqData) md := metadata.New(map[string]string{"env": "test"}) ctx := metadata.NewIncomingContext(context.Background(), md) @@ -146,6 +152,11 @@ func TestGetEvent(t *testing.T) { } func TestGetEventWithMasking(t *testing.T) { + var ( + cacheTTL = time.Minute + errCache = errors.New("test error") + ) + type seqDBArgs struct { req *seqapi.GetEventRequest resp *seqapi.GetEventResponse @@ -328,7 +339,7 @@ func TestGetEventWithMasking(t *testing.T) { Data: map[string]string{ eventField: eventVal, }, - Time: timestamppb.New(someMoment), + Time: timestamppb.New(testSomeMoment), } if shouldMask { event.Data[eventField] = "***" @@ -398,7 +409,7 @@ func TestGetEventWithMasking(t *testing.T) { Times(1) } - api := setupAPI(seqData) + api := setupTestAPI(seqData) req := &seqapi.GetEventRequest{Id: curEID} resp, err := api.GetEvent(context.Background(), req) diff --git a/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go b/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go index 5629fd2..162cf2c 100644 --- a/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go +++ b/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go @@ -19,6 +19,9 @@ import ( ) func TestServeFetchAsyncSearchResult(t *testing.T) { + var ( + meta = `{"some":"meta"}` + ) type mockArgs struct { req *seqapi.FetchAsyncSearchResultRequest err error @@ -36,7 +39,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "ok", req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -46,8 +49,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -71,7 +74,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -80,7 +83,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -104,14 +107,14 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Value: pointerTo(2), NotExists: 0, Quantiles: []float64{2, 1}, - Ts: timestamppb.New(someMoment), + Ts: timestamppb.New(testSomeMoment), }, { Key: "2", Value: pointerTo(8), NotExists: 1, Quantiles: []float64{7, 4}, - Ts: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Ts: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -122,15 +125,15 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Meta: meta, }, mockArgs: &mockArgs{ req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -140,7 +143,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "partial_response", req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -150,8 +153,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, @@ -164,7 +167,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, }, Total: 1, @@ -172,8 +175,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Meta: meta, @@ -184,7 +187,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -201,7 +204,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "err_svc", req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -209,7 +212,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { wantCode: codes.Internal, mockArgs: &mockArgs{ req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -223,20 +226,20 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) + seqData := test.APITestData{} + seqData.Mocks.AsyncSearchesSvc = svcMock if tt.mockArgs != nil { - ctrl := gomock.NewController(t) - svcMock := mock_asyncsearches.NewMockService(ctrl) - svcMock.EXPECT(). FetchAsyncSearchResult(gomock.Any(), tt.mockArgs.req). Return(tt.want, tt.mockArgs.err). Times(1) - seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) got, err := api.FetchAsyncSearchResult(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) @@ -250,9 +253,9 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { func TestServeFetchAsyncSearchResult_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) - _, err := api.FetchAsyncSearchResult(context.Background(), &seqapi.FetchAsyncSearchResultRequest{}) + _, err := api.FetchAsyncSearchResult(context.Background(), &seqapi.FetchAsyncSearchResultRequest{SearchId: testSearchID}) require.Error(t, err) require.Equal(t, status.Error(codes.Unimplemented, types.ErrAsyncSearchesDisabled.Error()), err) } diff --git a/internal/api/seqapi/v1/grpc/fields_test.go b/internal/api/seqapi/v1/grpc/fields_test.go index ac9afa8..f52149d 100644 --- a/internal/api/seqapi/v1/grpc/fields_test.go +++ b/internal/api/seqapi/v1/grpc/fields_test.go @@ -125,7 +125,7 @@ func TestGetFields(t *testing.T) { }, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) resp, err := api.GetFields(context.Background(), nil) require.Equal(t, tt.clientErr, err) @@ -135,6 +135,9 @@ func TestGetFields(t *testing.T) { } func TestGetFieldsCached(t *testing.T) { + var ( + ttl = 10 * time.Millisecond + ) responses := []*seqapi.GetFieldsResponse{ { Fields: []*seqapi.Field{ @@ -179,7 +182,7 @@ func TestGetFieldsCached(t *testing.T) { }, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) for _, r := range responses { resp, err := api.GetFields(context.Background(), nil) @@ -225,7 +228,7 @@ func TestGetPinnedFields(t *testing.T) { }, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) resp, err := api.GetPinnedFields(context.Background(), nil) require.NoError(t, err) diff --git a/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go b/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go index ffd077d..62302ef 100644 --- a/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go +++ b/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go @@ -19,6 +19,12 @@ import ( ) func TestServeGetAsyncSearchesList(t *testing.T) { + var ( + errorMsg = "some err" + mockUserName1 = "some_user_1" + mockUserName2 = "some_user_2" + mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" + ) type mockArgs struct { req *seqapi.GetAsyncSearchesListRequest err error @@ -39,18 +45,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -62,8 +68,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(someMoment.Add(-1 * time.Hour)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-1 * time.Hour)), + To: timestamppb.New(testSomeMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -76,9 +82,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(someMoment.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(300 * time.Second)), - CanceledAt: timestamppb.New(someMoment), + StartedAt: timestamppb.New(testSomeMoment.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(300 * time.Second)), + CanceledAt: timestamppb.New(testSomeMoment), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -100,18 +106,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -133,18 +139,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -181,21 +187,20 @@ func TestServeGetAsyncSearchesList(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) + seqData := test.APITestData{} + seqData.Mocks.AsyncSearchesSvc = svcMock if tt.mockArgs != nil { - ctrl := gomock.NewController(t) - svcMock := mock_asyncsearches.NewMockService(ctrl) - svcMock.EXPECT(). GetAsyncSearchesList(gomock.Any(), tt.mockArgs.req). Return(tt.want, tt.mockArgs.err). Times(1) - - seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) got, err := api.GetAsyncSearchesList(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) @@ -209,7 +214,7 @@ func TestServeGetAsyncSearchesList(t *testing.T) { func TestServeGetAsyncSearchesList_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) _, err := api.GetAsyncSearchesList(context.Background(), &seqapi.GetAsyncSearchesListRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/histogram_test.go b/internal/api/seqapi/v1/grpc/histogram_test.go index 54ed440..9e10f9e 100644 --- a/internal/api/seqapi/v1/grpc/histogram_test.go +++ b/internal/api/seqapi/v1/grpc/histogram_test.go @@ -15,6 +15,10 @@ import ( ) func TestGetHistogram(t *testing.T) { + var ( + query = "message:error" + interval = "2s" + ) tests := []struct { name string @@ -27,8 +31,8 @@ func TestGetHistogram(t *testing.T) { name: "ok", req: &seqapi.GetHistogramRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Interval: interval, }, want: &seqapi.GetHistogramResponse{ @@ -62,7 +66,7 @@ func TestGetHistogram(t *testing.T) { Times(1) seqData.Mocks.SeqDB = seqDbMock - api := setupAPI(seqData) + api := setupTestAPI(seqData) resp, err := api.GetHistogram(context.Background(), tt.req) require.Equal(t, tt.clientErr, err) diff --git a/internal/api/seqapi/v1/grpc/limits_test.go b/internal/api/seqapi/v1/grpc/limits_test.go index 0d9eb76..30892c6 100644 --- a/internal/api/seqapi/v1/grpc/limits_test.go +++ b/internal/api/seqapi/v1/grpc/limits_test.go @@ -51,7 +51,7 @@ func TestGetLimits(t *testing.T) { seqData := test.APITestData{ Cfg: tt.cfg, } - s := setupAPI(seqData) + s := setupTestAPI(seqData) resp, err := s.GetLimits(context.Background(), nil) require.NoError(t, err) diff --git a/internal/api/seqapi/v1/grpc/logs_lifespan_test.go b/internal/api/seqapi/v1/grpc/logs_lifespan_test.go index 28492ef..55570ce 100644 --- a/internal/api/seqapi/v1/grpc/logs_lifespan_test.go +++ b/internal/api/seqapi/v1/grpc/logs_lifespan_test.go @@ -21,6 +21,12 @@ import ( ) func TestGetLogsLifespan(t *testing.T) { + var ( + resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) + cacheKey = "logs_lifespan" + result = 10 * time.Hour + cacheTTL = time.Minute + ) unparsable := func(s string) bool { _, err := strconv.Atoi(s) return err != nil @@ -55,7 +61,7 @@ func TestGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), }, resp: &seqapi.GetLogsLifespanResponse{ Lifespan: durationpb.New(result), @@ -70,7 +76,7 @@ func TestGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), }, resp: &seqapi.GetLogsLifespanResponse{ Lifespan: durationpb.New(result), @@ -132,9 +138,9 @@ func TestGetLogsLifespan(t *testing.T) { } } - s := setupAPI(seqData) + s := setupTestAPI(seqData) s.nowFn = func() time.Time { - return someMoment.Add(result) + return testSomeMoment.Add(result) } resp, err := s.GetLogsLifespan(context.Background(), nil) diff --git a/internal/api/seqapi/v1/grpc/search_test.go b/internal/api/seqapi/v1/grpc/search_test.go index 4a26218..8523e2e 100644 --- a/internal/api/seqapi/v1/grpc/search_test.go +++ b/internal/api/seqapi/v1/grpc/search_test.go @@ -17,6 +17,10 @@ import ( ) func TestSearch(t *testing.T) { + var ( + query = "message:error" + limit int32 = 3 + ) tests := []struct { name string @@ -33,8 +37,8 @@ func TestSearch(t *testing.T) { name: "ok", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: limit, Offset: 0, WithTotal: true, @@ -48,7 +52,7 @@ func TestSearch(t *testing.T) { Order: seqapi.Order_ORDER_ASC, }, resp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), someMoment), + Events: test.MakeEvents(int(limit), testSomeMoment), Total: int64(limit), Histogram: test.MakeHistogram(2), Aggregations: test.MakeAggregations(2, 2, nil), @@ -104,8 +108,8 @@ func TestSearch(t *testing.T) { name: "err_offset_too_high", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: limit, Offset: 11, }, @@ -121,18 +125,18 @@ func TestSearch(t *testing.T) { name: "err_total_too_high", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: limit, Offset: 0, WithTotal: true, }, resp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), someMoment), + Events: test.MakeEvents(int(limit), testSomeMoment), Total: int64(limit) + 1, }, wantResp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), someMoment), + Events: test.MakeEvents(int(limit), testSomeMoment), Total: int64(limit) + 1, Error: &seqapi.Error{ Code: seqapi.ErrorCode_ERROR_CODE_QUERY_TOO_HEAVY, @@ -150,8 +154,8 @@ func TestSearch(t *testing.T) { name: "err_client", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: limit, Offset: 0, }, @@ -184,7 +188,7 @@ func TestSearch(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) resp, err := api.Search(context.Background(), tt.req) if tt.apiErr { require.NotNil(t, err) diff --git a/internal/api/seqapi/v1/grpc/start_async_search_test.go b/internal/api/seqapi/v1/grpc/start_async_search_test.go index 8b031d5..688b5be 100644 --- a/internal/api/seqapi/v1/grpc/start_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/start_async_search_test.go @@ -19,6 +19,10 @@ import ( ) func TestServeStartAsyncSearch(t *testing.T) { + var ( + query = "message:error" + meta = `{"some":"meta"}` + ) type mockArgs struct { resp *seqapi.StartAsyncSearchResponse err error @@ -38,8 +42,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ @@ -56,11 +60,11 @@ func TestServeStartAsyncSearch(t *testing.T) { Meta: meta, }, want: &seqapi.StartAsyncSearchResponse{ - SearchId: mockSearchID, + SearchId: testSearchID, }, mockArgs: &mockArgs{ resp: &seqapi.StartAsyncSearchResponse{ - SearchId: mockSearchID, + SearchId: testSearchID, }, }, }, @@ -69,8 +73,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ @@ -111,7 +115,7 @@ func TestServeStartAsyncSearch(t *testing.T) { seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) got, err := api.StartAsyncSearch(context.Background(), tt.req) require.Equal(t, tt.wantCode, status.Code(err)) @@ -125,7 +129,7 @@ func TestServeStartAsyncSearch(t *testing.T) { func TestServeStartAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) _, err := api.StartAsyncSearch(context.Background(), &seqapi.StartAsyncSearchRequest{}) require.Error(t, err) diff --git a/internal/api/seqapi/v1/grpc/test_data.go b/internal/api/seqapi/v1/grpc/test_data.go index fb03c16..3fdd0ff 100644 --- a/internal/api/seqapi/v1/grpc/test_data.go +++ b/internal/api/seqapi/v1/grpc/test_data.go @@ -7,36 +7,19 @@ import ( "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/config" "github.com/ozontech/seq-ui/internal/pkg/client/seqdb" + asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches" ) +// Shared test data. var ( - errSomethingWrong = errors.New("something happened wrong") - errCache = errors.New("test error") - errorMsg = "some err" - mockSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" - mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - id1 = "test1" - id2 = "test2" - id3 = "test3" - id4 = "test4" - query = "message:error" - cacheKey = "logs_lifespan" - targetBucketRate = "3s" - interval = "2s" - resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) - meta = `{"some":"meta"}` - someMoment = time.Now() - from = time.Now() - to = from.Add(time.Second) - cacheTTL = time.Minute - ttl = 10 * time.Millisecond - result = 10 * time.Hour - limit int32 = 3 + errSomethingWrong = errors.New("something happened wrong") + testSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" + testSomeMoment = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) + testFrom = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) + testTo = testFrom.Add(time.Second) ) -func setupAPI(data test.APITestData) *API { +func setupTestAPI(data test.APITestData) *API { // when test cases don't explicitly provide configuration if data.Cfg.SeqAPIOptions == nil { data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} @@ -48,16 +31,10 @@ func setupAPI(data test.APITestData) *API { seqDBClients[envConfig.SeqDB] = data.Mocks.SeqDB } - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, nil) -} - -func setupAPIWithAsyncSearches(data test.APITestData) *API { - if data.Cfg.SeqAPIOptions == nil { - data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} - } - seqDBClients := map[string]seqdb.Client{ - config.DefaultSeqDBClientID: data.Mocks.SeqDB, + var asyncSvc asyncsearches.Service + if data.Mocks.AsyncSearchesSvc != nil { + asyncSvc = data.Mocks.AsyncSearchesSvc } - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, data.Mocks.AsyncSearchesSvc) + return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, asyncSvc) } diff --git a/internal/api/seqapi/v1/http/aggregation_test.go b/internal/api/seqapi/v1/http/aggregation_test.go index 7b53e29..f95425b 100644 --- a/internal/api/seqapi/v1/http/aggregation_test.go +++ b/internal/api/seqapi/v1/http/aggregation_test.go @@ -35,16 +35,16 @@ func TestServeGetAggregation(t *testing.T) { { name: "ok_single_agg", req: getAggregationRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, AggField: "test_single", }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), AggField: "test_single", }, resp: &seqapi.GetAggregationResponse{ @@ -70,9 +70,9 @@ func TestServeGetAggregation(t *testing.T) { { name: "ok_multi_agg", req: getAggregationRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Aggregations: aggregationQueries{ {Field: "test_multi1"}, {Field: "test_multi2"}, @@ -81,9 +81,9 @@ func TestServeGetAggregation(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test_multi1"}, {Field: "test_multi2"}, @@ -114,9 +114,9 @@ func TestServeGetAggregation(t *testing.T) { { name: "ok_agg_quantile", req: getAggregationRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Aggregations: aggregationQueries{ { Field: "test_multi1", @@ -128,9 +128,9 @@ func TestServeGetAggregation(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ { Field: "test_multi1", @@ -175,16 +175,16 @@ func TestServeGetAggregation(t *testing.T) { { name: "err_partial_response", req: getAggregationRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, AggField: "test_err_partial", }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), AggField: "test_err_partial", }, resp: &seqapi.GetAggregationResponse{ @@ -210,9 +210,9 @@ func TestServeGetAggregation(t *testing.T) { { name: "err_aggs_limit_max", req: getAggregationRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Aggregations: aggregationQueries{{}, {}, {}}, }, wantErr: true, @@ -225,16 +225,16 @@ func TestServeGetAggregation(t *testing.T) { { name: "err_client", req: getAggregationRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, AggField: "test_err_client", }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), AggField: "test_err_client", }, err: errors.New("client error"), @@ -268,7 +268,7 @@ func TestServeGetAggregation(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAggregationRequest, getAggregationResponse]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/aggregation_ts_test.go b/internal/api/seqapi/v1/http/aggregation_ts_test.go index 8f9f99b..d911dff 100644 --- a/internal/api/seqapi/v1/http/aggregation_ts_test.go +++ b/internal/api/seqapi/v1/http/aggregation_ts_test.go @@ -31,7 +31,7 @@ func TestServeGetAggregationTs(t *testing.T) { aggQueriesRaw, err := json.Marshal(aggQueries) assert.NoError(t, err) return fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"aggregations":%s}`, - query, from.Format(time.RFC3339), to.Format(time.RFC3339), aggQueriesRaw) + testQuery, testFrom.Format(time.RFC3339), testTo.Format(time.RFC3339), aggQueriesRaw) } type mockArgs struct { @@ -70,9 +70,9 @@ func TestServeGetAggregationTs(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test_count1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, {Field: "test_count2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, @@ -81,9 +81,9 @@ func TestServeGetAggregationTs(t *testing.T) { resp: &seqapi.GetAggregationResponse{ Aggregation: test.MakeAggregation(3, &test.MakeAggOpts{ Ts: []*timestamppb.Timestamp{ - timestamppb.New(from.Add(time.Second)), - timestamppb.New(from.Add(2 * time.Second)), - timestamppb.New(from.Add(3 * time.Second)), + timestamppb.New(testFrom.Add(time.Second)), + timestamppb.New(testFrom.Add(2 * time.Second)), + timestamppb.New(testFrom.Add(3 * time.Second)), }, Values: []float64{ 1, @@ -93,9 +93,9 @@ func TestServeGetAggregationTs(t *testing.T) { }), Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ Ts: []*timestamppb.Timestamp{ - timestamppb.New(from.Add(time.Second)), - timestamppb.New(from.Add(2 * time.Second)), - timestamppb.New(from.Add(3 * time.Second)), + timestamppb.New(testFrom.Add(time.Second)), + timestamppb.New(testFrom.Add(2 * time.Second)), + timestamppb.New(testFrom.Add(3 * time.Second)), }, }), Error: &seqapi.Error{ @@ -133,9 +133,9 @@ func TestServeGetAggregationTs(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ {Field: "test_count1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval2}, {Field: "test_count2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval2, TargetBucketRate: &targetBucketRate}, @@ -144,9 +144,9 @@ func TestServeGetAggregationTs(t *testing.T) { resp: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ Ts: []*timestamppb.Timestamp{ - timestamppb.New(from.Add(time.Second)), - timestamppb.New(from.Add(2 * time.Second)), - timestamppb.New(from.Add(3 * time.Second)), + timestamppb.New(testFrom.Add(time.Second)), + timestamppb.New(testFrom.Add(2 * time.Second)), + timestamppb.New(testFrom.Add(3 * time.Second)), }, Values: []float64{ 3, @@ -183,9 +183,9 @@ func TestServeGetAggregationTs(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Aggregations: []*seqapi.AggregationQuery{ { Field: "test_quantile1", @@ -200,17 +200,17 @@ func TestServeGetAggregationTs(t *testing.T) { Aggregation: test.MakeAggregation(3, &test.MakeAggOpts{ Quantiles: []float64{100, 150}, Ts: []*timestamppb.Timestamp{ - timestamppb.New(from.Add(time.Second)), - timestamppb.New(from.Add(2 * time.Second)), - timestamppb.New(from.Add(3 * time.Second)), + timestamppb.New(testFrom.Add(time.Second)), + timestamppb.New(testFrom.Add(2 * time.Second)), + timestamppb.New(testFrom.Add(3 * time.Second)), }, }), Aggregations: test.MakeAggregations(1, 3, &test.MakeAggOpts{ Quantiles: []float64{100, 150}, Ts: []*timestamppb.Timestamp{ - timestamppb.New(from.Add(time.Second)), - timestamppb.New(from.Add(2 * time.Second)), - timestamppb.New(from.Add(3 * time.Second)), + timestamppb.New(testFrom.Add(time.Second)), + timestamppb.New(testFrom.Add(2 * time.Second)), + timestamppb.New(testFrom.Add(3 * time.Second)), }, }), Error: &seqapi.Error{ @@ -232,9 +232,9 @@ func TestServeGetAggregationTs(t *testing.T) { reqBody: formatReqBody(nil), mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), }, resp: &seqapi.GetAggregationResponse{ Error: &seqapi.Error{ @@ -289,9 +289,9 @@ func TestServeGetAggregationTs(t *testing.T) { reqBody: formatReqBody(nil), mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), }, err: errors.New("client error"), }, @@ -321,7 +321,7 @@ func TestServeGetAggregationTs(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/aggregation_ts", strings.NewReader(tt.reqBody)) httputil.DoTestHTTP(t, httputil.TestDataHTTP{ diff --git a/internal/api/seqapi/v1/http/cancel_async_search_test.go b/internal/api/seqapi/v1/http/cancel_async_search_test.go index fb54afd..e904a2b 100644 --- a/internal/api/seqapi/v1/http/cancel_async_search_test.go +++ b/internal/api/seqapi/v1/http/cancel_async_search_test.go @@ -31,11 +31,11 @@ func TestServeCancelAsyncSearch(t *testing.T) { }{ { name: "ok", - searchID: mockSearchID, + searchID: testSearchID, noResp: true, mockArgs: &mockArgs{ req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, resp: &seqapi.CancelAsyncSearchResponse{}, }, @@ -47,11 +47,11 @@ func TestServeCancelAsyncSearch(t *testing.T) { }, { name: "err_svc", - searchID: mockSearchID, + searchID: testSearchID, wantErr: true, mockArgs: &mockArgs{ req: &seqapi.CancelAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, err: errSomethingWrong, }, @@ -78,12 +78,12 @@ func TestServeCancelAsyncSearch(t *testing.T) { seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ Method: http.MethodPost, - Target: fmt.Sprintf("/seqapi/v1/async_search/%s/cancel", mockSearchID), - Handler: withAsyncSearchID(api.serveCancelAsyncSearch, tt.searchID), + Target: fmt.Sprintf("/seqapi/v1/async_search/%s/cancel", testSearchID), + Handler: withQueryParamID(api.serveCancelAsyncSearch, tt.searchID), WantErr: tt.wantErr, NoResp: tt.noResp, }) @@ -93,11 +93,11 @@ func TestServeCancelAsyncSearch(t *testing.T) { func TestServeCancelAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ Method: http.MethodPost, - Target: "/seqapi/v1/async_search/c9a34cf8-4c66-484e-9cc2-42979d848656/cancel", + Target: fmt.Sprintf("/seqapi/v1/async_search/%s/cancel", testSearchID), Handler: api.serveCancelAsyncSearch, WantErr: true, }) diff --git a/internal/api/seqapi/v1/http/cluster_status_test.go b/internal/api/seqapi/v1/http/cluster_status_test.go index 931406f..8d90ebb 100644 --- a/internal/api/seqapi/v1/http/cluster_status_test.go +++ b/internal/api/seqapi/v1/http/cluster_status_test.go @@ -30,23 +30,23 @@ func TestStatus(t *testing.T) { { name: "ok", want: statusResponse{ - OldestStorageTime: &someMoment, + OldestStorageTime: &testSomeMoment, NumberOfStores: 1, Stores: []storeStatus{ { Host: "host-0", - Values: &storeStatusValues{OldestTime: &someMoment}, + Values: &storeStatusValues{OldestTime: &testSomeMoment}, }, }, }, mockArgs: &mockArgs{ resp: &seqapi.StatusResponse{ NumberOfStores: 1, - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), Stores: []*seqapi.StoreStatus{ { Host: "host-0", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(someMoment)}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment)}, }, }, }, @@ -75,7 +75,7 @@ func TestStatus(t *testing.T) { Times(1) seqData.Mocks.SeqDB = seqDbMock - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, statusResponse]{ Method: http.MethodGet, diff --git a/internal/api/seqapi/v1/http/delete_async_search_test.go b/internal/api/seqapi/v1/http/delete_async_search_test.go index adec54b..a3802db 100644 --- a/internal/api/seqapi/v1/http/delete_async_search_test.go +++ b/internal/api/seqapi/v1/http/delete_async_search_test.go @@ -31,11 +31,11 @@ func TestServeDeleteAsyncSearch(t *testing.T) { }{ { name: "ok", - searchID: mockSearchID, + searchID: testSearchID, noResp: true, mockArgs: &mockArgs{ req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, resp: &seqapi.DeleteAsyncSearchResponse{}, }, @@ -47,11 +47,11 @@ func TestServeDeleteAsyncSearch(t *testing.T) { }, { name: "err_svc", - searchID: mockSearchID, + searchID: testSearchID, wantErr: true, mockArgs: &mockArgs{ req: &seqapi.DeleteAsyncSearchRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, }, err: errSomethingWrong, }, @@ -76,12 +76,12 @@ func TestServeDeleteAsyncSearch(t *testing.T) { seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ Method: http.MethodDelete, - Target: fmt.Sprintf("/seqapi/v1/async_search/%s", mockSearchID), - Handler: withAsyncSearchID(api.serveDeleteAsyncSearch, tt.searchID), + Target: fmt.Sprintf("/seqapi/v1/async_search/%s", testSearchID), + Handler: withQueryParamID(api.serveDeleteAsyncSearch, tt.searchID), WantErr: tt.wantErr, NoResp: tt.noResp, }) @@ -91,11 +91,11 @@ func TestServeDeleteAsyncSearch(t *testing.T) { func TestServeDeleteAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, struct{}]{ Method: http.MethodDelete, - Target: "/seqapi/v1/async_search/c9a34cf8-4c66-484e-9cc2-42979d848656", + Target: fmt.Sprintf("/seqapi/v1/async_search/%s", testSearchID), Handler: api.serveDeleteAsyncSearch, WantErr: true, }) diff --git a/internal/api/seqapi/v1/http/events_test.go b/internal/api/seqapi/v1/http/events_test.go index 78f4d4e..372ece9 100644 --- a/internal/api/seqapi/v1/http/events_test.go +++ b/internal/api/seqapi/v1/http/events_test.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -20,11 +21,19 @@ import ( ) func TestServeGetEvent(t *testing.T) { - event1 := test.MakeEvent(id1, 1, someMoment) + var ( + id1 = "test1" + id2 = "test2" + id3 = "test3" + id4 = "test4" + cacheTTL = time.Minute + ) + + event1 := test.MakeEvent(id1, 1, testSomeMoment) event1json, _ := proto.Marshal(event1) - event2 := test.MakeEvent(id2, 2, someMoment) + event2 := test.MakeEvent(id2, 2, testSomeMoment) event2json, _ := proto.Marshal(event2) - event3 := test.MakeEvent(id3, 0, someMoment) + event3 := test.MakeEvent(id3, 0, testSomeMoment) event3json, _ := proto.Marshal(event3) type mockArgs struct { @@ -141,12 +150,12 @@ func TestServeGetEvent(t *testing.T) { } } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getEventResponse]{ Method: http.MethodGet, Target: fmt.Sprintf("/seqapi/v1/events/%s", tt.id), - Handler: withEventID(api.serveGetEvent, tt.id), + Handler: withQueryParamID(api.serveGetEvent, tt.id), Want: tt.want, WantErr: tt.wantErr, }) @@ -155,6 +164,10 @@ func TestServeGetEvent(t *testing.T) { } func TestGetEventWithMasking(t *testing.T) { + var ( + errCache = errors.New("test error") + cacheTTL = time.Minute + ) type mockArgs struct { req *seqapi.GetEventRequest resp *seqapi.GetEventResponse @@ -338,7 +351,7 @@ func TestGetEventWithMasking(t *testing.T) { Data: map[string]string{ eventField: eventVal, }, - Time: timestamppb.New(someMoment), + Time: timestamppb.New(testSomeMoment), } if shouldMask { event.Data[eventField] = "***" @@ -413,12 +426,12 @@ func TestGetEventWithMasking(t *testing.T) { } seqData.Mocks.SeqDB = seqDbMock - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getEventResponse]{ Method: http.MethodGet, Target: fmt.Sprintf("/seqapi/v1/events/%s", curEID), - Handler: withEventID(api.serveGetEvent, curEID), + Handler: withQueryParamID(api.serveGetEvent, curEID), Want: curEData.want, WantErr: tt.wantErr, }) diff --git a/internal/api/seqapi/v1/http/export_test.go b/internal/api/seqapi/v1/http/export_test.go index 5ccb91e..3b8fb63 100644 --- a/internal/api/seqapi/v1/http/export_test.go +++ b/internal/api/seqapi/v1/http/export_test.go @@ -32,9 +32,9 @@ func TestServeExport(t *testing.T) { { name: "ok_jsonl", req: exportRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 50, Offset: 0, }, @@ -46,9 +46,9 @@ func TestServeExport(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 50, Offset: 0, }, @@ -57,9 +57,9 @@ func TestServeExport(t *testing.T) { { name: "ok_csv", req: exportRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 50, Offset: 0, Format: efCSV, @@ -73,9 +73,9 @@ func TestServeExport(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 50, Offset: 0, Format: seqapi.ExportFormat_EXPORT_FORMAT_CSV, @@ -86,9 +86,9 @@ func TestServeExport(t *testing.T) { { name: "err_parallel_limited", req: exportRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 0, Offset: 0, }, @@ -102,9 +102,9 @@ func TestServeExport(t *testing.T) { { name: "err_export_limit_max", req: exportRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 10, Offset: 0, }, @@ -119,9 +119,9 @@ func TestServeExport(t *testing.T) { { name: "err_csv_empty_fields", req: exportRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 10, Offset: 0, Format: efCSV, @@ -137,9 +137,9 @@ func TestServeExport(t *testing.T) { { name: "err_client", req: exportRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 50, Offset: 0, }, @@ -152,9 +152,9 @@ func TestServeExport(t *testing.T) { wantErr: true, mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 50, Offset: 0, }, @@ -183,7 +183,7 @@ func TestServeExport(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[exportRequest, struct{}]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/fetch_async_search_result_test.go b/internal/api/seqapi/v1/http/fetch_async_search_result_test.go index fe7660b..faaa7fb 100644 --- a/internal/api/seqapi/v1/http/fetch_async_search_result_test.go +++ b/internal/api/seqapi/v1/http/fetch_async_search_result_test.go @@ -34,7 +34,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "ok", req: fetchAsyncSearchResultRequest{ - SearchID: mockSearchID, + SearchID: testSearchID, Limit: 2, Offset: 10, Order: oDESC, @@ -44,8 +44,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -75,7 +75,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -84,7 +84,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -123,19 +123,19 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Key: "33", Value: pointerTo[float64](2), NotExists: 0, - Ts: timestamppb.New(someMoment.Add(-30 * time.Second)), + Ts: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), }, { Key: "33", Value: pointerTo[float64](5), NotExists: 0, - Ts: timestamppb.New(someMoment), + Ts: timestamppb.New(testSomeMoment), }, { Key: "22", Value: pointerTo[float64](8), NotExists: 1, - Ts: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Ts: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -146,8 +146,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -156,7 +156,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -166,8 +166,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -197,7 +197,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -206,7 +206,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -245,19 +245,19 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Key: "33", Value: pointerTo[float64](2), NotExists: 0, - Ts: timestamppb.New(someMoment.Add(-30 * time.Second)), + Ts: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), }, { Key: "33", Value: pointerTo[float64](5), NotExists: 0, - Ts: timestamppb.New(someMoment), + Ts: timestamppb.New(testSomeMoment), }, { Key: "22", Value: pointerTo[float64](8), NotExists: 1, - Ts: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Ts: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -268,8 +268,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -281,7 +281,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "partial_response", req: fetchAsyncSearchResultRequest{ - SearchID: mockSearchID, + SearchID: testSearchID, Limit: 2, Offset: 10, Order: oDESC, @@ -291,8 +291,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, @@ -305,7 +305,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -314,7 +314,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -323,8 +323,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -334,7 +334,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.FetchAsyncSearchResultRequest{ - SearchId: mockSearchID, + SearchId: testSearchID, Limit: 2, Offset: 10, Order: seqapi.Order_ORDER_DESC, @@ -344,8 +344,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, @@ -358,7 +358,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(someMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -367,7 +367,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(someMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), }, }, Total: 2, @@ -376,8 +376,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -390,7 +390,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "err_limit", req: fetchAsyncSearchResultRequest{ - SearchID: mockSearchID, + SearchID: testSearchID, Limit: -10, Offset: 20, }, @@ -399,7 +399,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { { name: "err_offset", req: fetchAsyncSearchResultRequest{ - SearchID: mockSearchID, + SearchID: testSearchID, Limit: 10, Offset: -20, }, @@ -418,21 +418,20 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) + seqData := test.APITestData{} + seqData.Mocks.AsyncSearchesSvc = svcMock if tt.mockArgs != nil { - ctrl := gomock.NewController(t) - svcMock := mock_asyncsearches.NewMockService(ctrl) - svcMock.EXPECT(). FetchAsyncSearchResult(gomock.Any(), tt.mockArgs.req). Return(tt.mockArgs.resp, tt.mockArgs.err). Times(1) - - seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[fetchAsyncSearchResultRequest, fetchAsyncSearchResultResponse]{ Method: http.MethodPost, @@ -448,7 +447,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { func TestServeFetchAsyncSearchResult_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[fetchAsyncSearchResultRequest, struct{}]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/fields_test.go b/internal/api/seqapi/v1/http/fields_test.go index bb312ef..81bfb7b 100644 --- a/internal/api/seqapi/v1/http/fields_test.go +++ b/internal/api/seqapi/v1/http/fields_test.go @@ -121,7 +121,7 @@ func TestServeGetFields(t *testing.T) { Times(1) seqData.Mocks.SeqDB = seqDbMock - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ Method: http.MethodGet, @@ -135,6 +135,10 @@ func TestServeGetFields(t *testing.T) { } func TestServeGetFieldsCached(t *testing.T) { + var ( + ttl = 5 * time.Millisecond + ) + tests := []struct { name string @@ -203,7 +207,7 @@ func TestServeGetFieldsCached(t *testing.T) { }, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ Method: http.MethodGet, @@ -258,7 +262,7 @@ func TestServeGetPinnedFields(t *testing.T) { }, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getFieldsResponse]{ Method: http.MethodGet, diff --git a/internal/api/seqapi/v1/http/get_async_searches_list_test.go b/internal/api/seqapi/v1/http/get_async_searches_list_test.go index 0ad5e72..d8fbcd8 100644 --- a/internal/api/seqapi/v1/http/get_async_searches_list_test.go +++ b/internal/api/seqapi/v1/http/get_async_searches_list_test.go @@ -2,6 +2,7 @@ package http import ( "net/http" + "strings" "testing" "time" @@ -17,6 +18,11 @@ import ( func TestServeGetAsyncSearchesList(t *testing.T) { statusDone := asyncSearchStatus("done") + mockUserName1 := "some_user_1" + mockUserName2 := "some_user_2" + tooLongQuery := strings.Repeat("message:error and level:3", 41) + errorMsg := "some error" + mockSearchID2 := "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" type mockArgs struct { req *seqapi.GetAsyncSearchesListRequest @@ -39,18 +45,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -62,8 +68,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(someMoment.Add(-1 * time.Hour)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-1 * time.Hour)), + To: timestamppb.New(testSomeMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -77,9 +83,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(someMoment.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(300 * time.Second)), - CanceledAt: timestamppb.New(someMoment), + StartedAt: timestamppb.New(testSomeMoment.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(300 * time.Second)), + CanceledAt: timestamppb.New(testSomeMoment), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -94,18 +100,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -117,8 +123,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(someMoment.Add(-1 * time.Hour)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-1 * time.Hour)), + To: timestamppb.New(testSomeMoment), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -132,9 +138,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(someMoment.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(300 * time.Second)), - CanceledAt: timestamppb.New(someMoment), + StartedAt: timestamppb.New(testSomeMoment.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(300 * time.Second)), + CanceledAt: timestamppb.New(testSomeMoment), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -157,18 +163,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -188,18 +194,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -217,18 +223,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -244,18 +250,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -290,18 +296,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { want: getAsyncSearchesListResponseFromProto(&seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: tooLongQuery, - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -317,18 +323,18 @@ func TestServeGetAsyncSearchesList(t *testing.T) { resp: &seqapi.GetAsyncSearchesListResponse{ Searches: []*seqapi.GetAsyncSearchesListResponse_ListItem{ { - SearchId: mockSearchID, + SearchId: testSearchID, Status: seqapi.AsyncSearchStatus_ASYNC_SEARCH_STATUS_DONE, Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: tooLongQuery, - From: timestamppb.New(someMoment.Add(-15 * time.Minute)), - To: timestamppb.New(someMoment), + From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), + To: timestamppb.New(testSomeMoment), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(someMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(someMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -347,20 +353,19 @@ func TestServeGetAsyncSearchesList(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() + ctrl := gomock.NewController(t) + svcMock := mock_asyncsearches.NewMockService(ctrl) seqData := test.APITestData{} + seqData.Mocks.AsyncSearchesSvc = svcMock if tt.mockArgs != nil { - ctrl := gomock.NewController(t) - - svcMock := mock_asyncsearches.NewMockService(ctrl) svcMock.EXPECT(). GetAsyncSearchesList(gomock.Any(), tt.mockArgs.req). Return(tt.mockArgs.resp, tt.mockArgs.err). Times(1) - seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAsyncSearchesListRequest, getAsyncSearchesListResponse]{ Method: http.MethodPost, @@ -376,7 +381,7 @@ func TestServeGetAsyncSearchesList(t *testing.T) { func TestServeGetAsyncSearchesList_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getAsyncSearchesListRequest, struct{}]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/get_envs_test.go b/internal/api/seqapi/v1/http/get_envs_test.go index 192f55d..3ede5d5 100644 --- a/internal/api/seqapi/v1/http/get_envs_test.go +++ b/internal/api/seqapi/v1/http/get_envs_test.go @@ -152,7 +152,7 @@ func TestServeGetEnvs(t *testing.T) { Cfg: tt.cfg, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getEnvsResponse]{ Method: http.MethodGet, diff --git a/internal/api/seqapi/v1/http/histogram_test.go b/internal/api/seqapi/v1/http/histogram_test.go index ca14fa1..814d0b8 100644 --- a/internal/api/seqapi/v1/http/histogram_test.go +++ b/internal/api/seqapi/v1/http/histogram_test.go @@ -33,9 +33,9 @@ func TestServeGetHistogram(t *testing.T) { { name: "ok", req: getHistogramRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Interval: "5s", }, want: getHistogramResponse{ @@ -50,9 +50,9 @@ func TestServeGetHistogram(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Interval: "5s", }, resp: &seqapi.GetHistogramResponse{ @@ -66,9 +66,9 @@ func TestServeGetHistogram(t *testing.T) { { name: "err_partial_response", req: getHistogramRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Interval: "10s", }, want: getHistogramResponse{ @@ -80,9 +80,9 @@ func TestServeGetHistogram(t *testing.T) { }, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Interval: "10s", }, resp: &seqapi.GetHistogramResponse{ @@ -97,17 +97,17 @@ func TestServeGetHistogram(t *testing.T) { { name: "err_client", req: getHistogramRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Interval: "20s", }, wantErr: true, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Interval: "20s", }, err: errors.New("client error"), @@ -133,7 +133,7 @@ func TestServeGetHistogram(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[getHistogramRequest, getHistogramResponse]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/limits_test.go b/internal/api/seqapi/v1/http/limits_test.go index afb1e87..cf339e4 100644 --- a/internal/api/seqapi/v1/http/limits_test.go +++ b/internal/api/seqapi/v1/http/limits_test.go @@ -52,7 +52,7 @@ func TestServeGetLimits(t *testing.T) { Cfg: tt.cfg, } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getLimitsResponse]{ Method: http.MethodGet, diff --git a/internal/api/seqapi/v1/http/logs_lifespan_test.go b/internal/api/seqapi/v1/http/logs_lifespan_test.go index fcce6c6..13ef59e 100644 --- a/internal/api/seqapi/v1/http/logs_lifespan_test.go +++ b/internal/api/seqapi/v1/http/logs_lifespan_test.go @@ -20,6 +20,13 @@ import ( ) func TestServeGetLogsLifespan(t *testing.T) { + var ( + resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) + cacheKey = "logs_lifespan" + result = 10 * time.Hour + cacheTTL = time.Minute + ) + unparsable := func(s string) bool { _, err := strconv.Atoi(s) return err != nil @@ -53,7 +60,7 @@ func TestServeGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), }, want: getLogsLifespanResponse{Lifespan: 36000}, }, @@ -66,7 +73,7 @@ func TestServeGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(someMoment), + OldestStorageTime: timestamppb.New(testSomeMoment), }, want: getLogsLifespanResponse{Lifespan: 36000}, }, @@ -128,9 +135,9 @@ func TestServeGetLogsLifespan(t *testing.T) { } } - api := setupAPI(seqData) + api := setupTestAPI(seqData) api.nowFn = func() time.Time { - return someMoment.Add(result) + return testSomeMoment.Add(result) } httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getLogsLifespanResponse]{ diff --git a/internal/api/seqapi/v1/http/search_test.go b/internal/api/seqapi/v1/http/search_test.go index 5defcaf..c59c25b 100644 --- a/internal/api/seqapi/v1/http/search_test.go +++ b/internal/api/seqapi/v1/http/search_test.go @@ -3,6 +3,7 @@ package http import ( "net/http" "testing" + "time" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -16,6 +17,10 @@ import ( ) func TestServeSearch(t *testing.T) { + var ( + eventTime = testFrom.Add(time.Millisecond) + ) + type mockArgs struct { req *seqapi.SearchRequest resp *seqapi.SearchResponse @@ -35,9 +40,9 @@ func TestServeSearch(t *testing.T) { { name: "ok_simple", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, }, want: searchResponse{ @@ -52,9 +57,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, }, @@ -69,9 +74,9 @@ func TestServeSearch(t *testing.T) { { name: "ok_with_total", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, WithTotal: true, }, @@ -88,9 +93,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, WithTotal: true, @@ -107,9 +112,9 @@ func TestServeSearch(t *testing.T) { { name: "ok_order_asc", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, Order: oASC, }, @@ -125,9 +130,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, Order: seqapi.Order_ORDER_ASC, @@ -143,9 +148,9 @@ func TestServeSearch(t *testing.T) { { name: "ok_with_hist", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, Histogram: struct { Interval string "json:\"interval\"" @@ -164,9 +169,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, Histogram: &seqapi.SearchRequest_Histogram{ @@ -185,9 +190,9 @@ func TestServeSearch(t *testing.T) { { name: "ok_with_aggs", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, Aggregations: aggregationQueries{ { @@ -212,9 +217,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, Aggregations: []*seqapi.AggregationQuery{ @@ -239,9 +244,9 @@ func TestServeSearch(t *testing.T) { { name: "ok_empty_events", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, }, want: searchResponse{ @@ -256,9 +261,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, }, @@ -273,9 +278,9 @@ func TestServeSearch(t *testing.T) { { name: "err_partial_response", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, }, want: searchResponse{ @@ -290,9 +295,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, }, @@ -309,9 +314,9 @@ func TestServeSearch(t *testing.T) { { name: "err_search_limit_zero", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 0, }, wantErr: true, @@ -319,9 +324,9 @@ func TestServeSearch(t *testing.T) { { name: "err_search_limit_max", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 10, }, cfg: config.SeqAPI{ @@ -334,9 +339,9 @@ func TestServeSearch(t *testing.T) { { name: "err_aggs_limit_max", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, Aggregations: aggregationQueries{{}, {}, {}}, }, @@ -351,9 +356,9 @@ func TestServeSearch(t *testing.T) { { name: "err_offset_too_high", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, Offset: 11, }, @@ -368,9 +373,9 @@ func TestServeSearch(t *testing.T) { { name: "err_total_too_high", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, WithTotal: true, }, @@ -388,9 +393,9 @@ func TestServeSearch(t *testing.T) { }), mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, WithTotal: true, @@ -408,9 +413,9 @@ func TestServeSearch(t *testing.T) { { name: "err_client", req: searchRequest{ - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, Limit: 3, }, cfg: test.SetCfgDefaults(config.SeqAPI{ @@ -421,9 +426,9 @@ func TestServeSearch(t *testing.T) { wantErr: true, mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), Limit: 3, Offset: 0, }, @@ -452,7 +457,7 @@ func TestServeSearch(t *testing.T) { seqData.Mocks.SeqDB = seqDbMock } - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[searchRequest, searchResponse]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/start_async_search_test.go b/internal/api/seqapi/v1/http/start_async_search_test.go index f0bdde5..0797b54 100644 --- a/internal/api/seqapi/v1/http/start_async_search_test.go +++ b/internal/api/seqapi/v1/http/start_async_search_test.go @@ -16,6 +16,10 @@ import ( ) func TestServeStartAsyncSearch(t *testing.T) { + var ( + meta = `{"some":"meta"}` + ) + type mockArgs struct { req *seqapi.StartAsyncSearchRequest resp *seqapi.StartAsyncSearchResponse @@ -35,9 +39,9 @@ func TestServeStartAsyncSearch(t *testing.T) { name: "ok", req: startAsyncSearchRequest{ Retention: "60s", - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, WithDocs: true, Size: 100, Meta: meta, @@ -57,14 +61,14 @@ func TestServeStartAsyncSearch(t *testing.T) { }, }, want: startAsyncSearchResponse{ - SearchID: mockSearchID, + SearchID: testSearchID, }, mockArgs: &mockArgs{ req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ @@ -82,7 +86,7 @@ func TestServeStartAsyncSearch(t *testing.T) { Meta: meta, }, resp: &seqapi.StartAsyncSearchResponse{ - SearchId: mockSearchID, + SearchId: testSearchID, }, }, }, @@ -90,9 +94,9 @@ func TestServeStartAsyncSearch(t *testing.T) { name: "err_svc", req: startAsyncSearchRequest{ Retention: "60s", - Query: query, - From: from, - To: to, + Query: testQuery, + From: testFrom, + To: testTo, WithDocs: true, Size: 100, Meta: meta, @@ -115,9 +119,9 @@ func TestServeStartAsyncSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), - Query: query, - From: timestamppb.New(from), - To: timestamppb.New(to), + Query: testQuery, + From: timestamppb.New(testFrom), + To: timestamppb.New(testTo), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ @@ -157,7 +161,7 @@ func TestServeStartAsyncSearch(t *testing.T) { seqData.Mocks.AsyncSearchesSvc = svcMock } - api := setupAPIWithAsyncSearches(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[startAsyncSearchRequest, startAsyncSearchResponse]{ Method: http.MethodPost, @@ -173,7 +177,7 @@ func TestServeStartAsyncSearch(t *testing.T) { func TestServeStartAsyncSearch_Disabled(t *testing.T) { seqData := test.APITestData{} - api := setupAPI(seqData) + api := setupTestAPI(seqData) httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[startAsyncSearchRequest, struct{}]{ Method: http.MethodPost, diff --git a/internal/api/seqapi/v1/http/test_data.go b/internal/api/seqapi/v1/http/test_data.go index e5ccbac..6135d38 100644 --- a/internal/api/seqapi/v1/http/test_data.go +++ b/internal/api/seqapi/v1/http/test_data.go @@ -4,7 +4,6 @@ import ( "context" "errors" "net/http" - "strings" "time" "github.com/go-chi/chi/v5" @@ -12,35 +11,20 @@ import ( "github.com/ozontech/seq-ui/internal/api/seqapi/v1/test" "github.com/ozontech/seq-ui/internal/app/config" "github.com/ozontech/seq-ui/internal/pkg/client/seqdb" + asyncsearches "github.com/ozontech/seq-ui/internal/pkg/service/async_searches" ) +// Shared test data. var ( errSomethingWrong = errors.New("something happened wrong") - errCache = errors.New("test error") - tooLongQuery = strings.Repeat("message:error and level:3", 41) - errorMsg = "some error" - query = "message:error" - id1 = "test1" - id2 = "test2" - id3 = "test3" - id4 = "test4" - mockSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" - mockSearchID2 = "9e4c068e-d4f4-4a5d-be27-a6524a70d70d" - mockUserName1 = "some_user_1" - mockUserName2 = "some_user_2" - meta = `{"some":"meta"}` - resultStr = "36000" // 10(h) * 60(min/h) * 60(sec/min) - cacheKey = "logs_lifespan" - from = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - eventTime = from.Add(time.Millisecond) - someMoment = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - to = from.Add(time.Second) - cacheTTL = time.Minute - ttl = 5 * time.Millisecond - result = 10 * time.Hour + testSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" + testQuery = "message:error" + testFrom = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) + testTo = testFrom.Add(time.Second) + testSomeMoment = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) ) -func setupAPI(data test.APITestData) *API { +func setupTestAPI(data test.APITestData) *API { // when test cases don't explicitly provide configuration. if data.Cfg.SeqAPIOptions == nil { data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} @@ -52,30 +36,15 @@ func setupAPI(data test.APITestData) *API { seqDBClients[envConfig.SeqDB] = data.Mocks.SeqDB } - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, nil) -} - -func setupAPIWithAsyncSearches(data test.APITestData) *API { - if data.Cfg.SeqAPIOptions == nil { - data.Cfg.SeqAPIOptions = &config.SeqAPIOptions{} + var asyncSvc asyncsearches.Service + if data.Mocks.AsyncSearchesSvc != nil { + asyncSvc = data.Mocks.AsyncSearchesSvc } - seqDBClients := map[string]seqdb.Client{ - config.DefaultSeqDBClientID: data.Mocks.SeqDB, - } - - return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, data.Mocks.AsyncSearchesSvc) -} -func withAsyncSearchID(h http.HandlerFunc, id string) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - rCtx := chi.NewRouteContext() - rCtx.URLParams.Add("id", id) - r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rCtx)) - h(w, r) - } + return New(data.Cfg, seqDBClients, data.Mocks.Cache, data.Mocks.Cache, asyncSvc) } -func withEventID(h http.HandlerFunc, id string) http.HandlerFunc { +func withQueryParamID(h http.HandlerFunc, id string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { rCtx := chi.NewRouteContext() rCtx.URLParams.Add("id", id) diff --git a/internal/api/userprofile/v1/grpc/api.go b/internal/api/userprofile/v1/grpc/api.go index 05e765b..c3ff3c6 100644 --- a/internal/api/userprofile/v1/grpc/api.go +++ b/internal/api/userprofile/v1/grpc/api.go @@ -1,17 +1,17 @@ package grpc import ( - userprofilesservice "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" - "github.com/ozontech/seq-ui/pkg/userprofile/v1" + "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" + api "github.com/ozontech/seq-ui/pkg/userprofile/v1" ) type API struct { - userprofile.UnimplementedUserProfileServiceServer + api.UnimplementedUserProfileServiceServer - service userprofilesservice.Service + service userprofile.Service } -func New(svc userprofilesservice.Service) *API { +func New(svc userprofile.Service) *API { return &API{ service: svc, } diff --git a/internal/api/userprofile/v1/grpc/favorite_queries_test.go b/internal/api/userprofile/v1/grpc/favorite_queries_test.go index bf5e88f..805ba84 100644 --- a/internal/api/userprofile/v1/grpc/favorite_queries_test.go +++ b/internal/api/userprofile/v1/grpc/favorite_queries_test.go @@ -14,6 +14,11 @@ import ( ) func TestGetFavoriteQueries(t *testing.T) { + var ( + relativeFrom uint64 = 300 + queryName = "my query" + ) + type mockArgs struct { req types.GetFavoriteQueriesRequest resp types.FavoriteQueries @@ -97,7 +102,7 @@ func TestGetFavoriteQueries(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). @@ -119,6 +124,13 @@ func TestGetFavoriteQueries(t *testing.T) { } func TestCreateFavoriteQuery(t *testing.T) { + var ( + queryID int64 = 1 + relativeFrom uint64 = 300 + query = "test" + queryName = "my query" + ) + type mockArgs struct { req types.GetOrCreateFavoriteQueryRequest resp int64 @@ -171,7 +183,7 @@ func TestCreateFavoriteQuery(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). @@ -193,6 +205,10 @@ func TestCreateFavoriteQuery(t *testing.T) { } func TestDeleteFavoriteQuery(t *testing.T) { + var ( + queryID int64 = 1 + ) + type mockArgs struct { req types.DeleteFavoriteQueryRequest err error @@ -239,7 +255,7 @@ func TestDeleteFavoriteQuery(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/userprofile/v1/grpc/test_data.go b/internal/api/userprofile/v1/grpc/test_data.go index 6198a91..8d79006 100644 --- a/internal/api/userprofile/v1/grpc/test_data.go +++ b/internal/api/userprofile/v1/grpc/test_data.go @@ -11,20 +11,12 @@ import ( mock "github.com/ozontech/seq-ui/internal/pkg/service/userprofile/mock" ) +// Shared test data. var ( - errSomethingWrong = errors.New("something happened wrong") - queryID int64 = 1 - relativeFrom uint64 = 300 - userName = "unnamed" - query = "test" - queryName = "my query" - timezone = "UTC" - validTimezone = "Europe/Moscow" - onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` - logColumns = []string{"val1", "val2"} + errSomethingWrong = errors.New("something happened wrong") ) -func setupAPI(t *testing.T) (*API, *mock.MockService) { +func setupTestAPI(t *testing.T) (*API, *mock.MockService) { ctrl := gomock.NewController(t) mockedSvc := mock.NewMockService(ctrl) return New(mockedSvc), mockedSvc diff --git a/internal/api/userprofile/v1/grpc/user_profiles_test.go b/internal/api/userprofile/v1/grpc/user_profiles_test.go index 125ba07..4913bb6 100644 --- a/internal/api/userprofile/v1/grpc/user_profiles_test.go +++ b/internal/api/userprofile/v1/grpc/user_profiles_test.go @@ -13,6 +13,13 @@ import ( ) func TestGetUserProfile(t *testing.T) { + var ( + userName = "unnamed" + timezone = "UTC" + onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` + logColumns = []string{"val1", "val2"} + ) + type mockArgs struct { req types.GetOrCreateUserProfileRequest resp types.UserProfile @@ -64,7 +71,7 @@ func TestGetUserProfile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). @@ -87,6 +94,13 @@ func TestGetUserProfile(t *testing.T) { } func TestUpdateUserProfile(t *testing.T) { + var ( + userName = "unnamed" + validTimezone = "Europe/Moscow" + onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` + logColumns = []string{"val1", "val2"} + ) + type mockArgs struct { req types.UpdateUserProfileRequest err error @@ -139,7 +153,7 @@ func TestUpdateUserProfile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/userprofile/v1/http/api.go b/internal/api/userprofile/v1/http/api.go index 08865be..59377eb 100644 --- a/internal/api/userprofile/v1/http/api.go +++ b/internal/api/userprofile/v1/http/api.go @@ -3,7 +3,7 @@ package http import ( "github.com/go-chi/chi/v5" - userprofile "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" + "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" ) type API struct { diff --git a/internal/api/userprofile/v1/http/favorite_queries_test.go b/internal/api/userprofile/v1/http/favorite_queries_test.go index 8497620..ccb6189 100644 --- a/internal/api/userprofile/v1/http/favorite_queries_test.go +++ b/internal/api/userprofile/v1/http/favorite_queries_test.go @@ -13,6 +13,10 @@ import ( ) func TestServeGetFavoriteQueries(t *testing.T) { + var ( + relativeFrom = "300" + ) + type mockArgs struct { req types.GetFavoriteQueriesRequest resp types.FavoriteQueries @@ -59,7 +63,7 @@ func TestServeGetFavoriteQueries(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). @@ -80,6 +84,12 @@ func TestServeGetFavoriteQueries(t *testing.T) { } func TestServeCreateFavoriteQuery(t *testing.T) { + var ( + relativeFrom = "300" + query = "test" + queryName = "my query" + ) + type mockArgs struct { req types.GetOrCreateFavoriteQueryRequest resp int64 @@ -127,7 +137,7 @@ func TestServeCreateFavoriteQuery(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). @@ -185,7 +195,7 @@ func TestServeDeleteFavoriteQuery(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/userprofile/v1/http/test_data.go b/internal/api/userprofile/v1/http/test_data.go index 69b4391..71b8e99 100644 --- a/internal/api/userprofile/v1/http/test_data.go +++ b/internal/api/userprofile/v1/http/test_data.go @@ -13,19 +13,12 @@ import ( mock "github.com/ozontech/seq-ui/internal/pkg/service/userprofile/mock" ) +// Shared test data. var ( errSomethingWrong = errors.New("something happened wrong") - userName = "unnamed" - relativeFrom = "300" - query = "test" - queryName = "my query" - timezone = "UTC" - validTimezone = "Europe/Moscow" - onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` - logColumns = []string{"val1", "val2"} ) -func setupAPI(t *testing.T) (*API, *mock.MockService) { +func setupTestAPI(t *testing.T) (*API, *mock.MockService) { ctrl := gomock.NewController(t) mockedSvc := mock.NewMockService(ctrl) return New(mockedSvc), mockedSvc diff --git a/internal/api/userprofile/v1/http/user_profiles_test.go b/internal/api/userprofile/v1/http/user_profiles_test.go index 5a31351..2f41d09 100644 --- a/internal/api/userprofile/v1/http/user_profiles_test.go +++ b/internal/api/userprofile/v1/http/user_profiles_test.go @@ -11,6 +11,13 @@ import ( ) func TestServeGetUserProfile(t *testing.T) { + var ( + userName = "unnamed" + timezone = "UTC" + onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` + logColumns = []string{"val1", "val2"} + ) + type mockArgs struct { req types.GetOrCreateUserProfileRequest resp types.UserProfile @@ -61,7 +68,7 @@ func TestServeGetUserProfile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). @@ -82,6 +89,13 @@ func TestServeGetUserProfile(t *testing.T) { } func TestServeUpdateUserProfile(t *testing.T) { + var ( + userName = "unnamed" + validTimezone = "Europe/Moscow" + onboardingVersion = `{"name1": "ver1", "name2": "ver2"}` + logColumns = []string{"val1", "val2"} + ) + type mockArgs struct { req types.UpdateUserProfileRequest err error @@ -139,7 +153,7 @@ func TestServeUpdateUserProfile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - api, mockedSvc := setupAPI(t) + api, mockedSvc := setupTestAPI(t) if tt.mockArgs != nil { mockedSvc.EXPECT(). diff --git a/internal/api/userprofile/v1/userprofile.go b/internal/api/userprofile/v1/userprofile.go index fe0cccd..803a4d2 100644 --- a/internal/api/userprofile/v1/userprofile.go +++ b/internal/api/userprofile/v1/userprofile.go @@ -5,7 +5,7 @@ import ( grpc_api "github.com/ozontech/seq-ui/internal/api/userprofile/v1/grpc" http_api "github.com/ozontech/seq-ui/internal/api/userprofile/v1/http" - userprofile "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" + "github.com/ozontech/seq-ui/internal/pkg/service/userprofile" ) type UserProfile struct { diff --git a/internal/pkg/service/profiles/profiles.go b/internal/pkg/service/profiles/profiles.go index abe8d0e..91c66fe 100644 --- a/internal/pkg/service/profiles/profiles.go +++ b/internal/pkg/service/profiles/profiles.go @@ -7,31 +7,35 @@ import ( "github.com/ozontech/seq-ui/internal/app/types" ) -type UserProfileService interface { +type userProfileService interface { GetOrCreateUserProfile(context.Context, types.GetOrCreateUserProfileRequest) (types.UserProfile, error) } -var profile *Profiles +var profile *profiles -func InitProfiles(svc UserProfileService) { - profile = New(svc) +func InitProfiles(svc userProfileService) { + profile = &profiles{ + idByName: make(map[string]int64), + service: svc, + } } -type Profiles struct { +type profiles struct { idByName map[string]int64 // map UserName->UserProfileId mx sync.RWMutex - service UserProfileService + service userProfileService } -func New(svc UserProfileService) *Profiles { - return &Profiles{ - idByName: make(map[string]int64), - service: svc, - } +func GetIDFromContext(ctx context.Context) (int64, error) { + return profile.GeIDFromContext(ctx) +} + +func SetID(userName string, userProfileID int64) { + profile.SetID(userName, userProfileID) } -func (p *Profiles) GeIDFromContext(ctx context.Context) (int64, error) { +func (p *profiles) GeIDFromContext(ctx context.Context) (int64, error) { userName, err := types.GetUserKey(ctx) if err != nil { return 0, err @@ -45,7 +49,7 @@ func (p *Profiles) GeIDFromContext(ctx context.Context) (int64, error) { return id, nil } -func (p *Profiles) GetID(userName string) (int64, error) { +func (p *profiles) GetID(userName string) (int64, error) { p.mx.RLock() id, ok := p.idByName[userName] p.mx.RUnlock() @@ -71,7 +75,7 @@ func (p *Profiles) GetID(userName string) (int64, error) { return id, nil } -func (p *Profiles) SetID(userName string, userProfileID int64) { +func (p *profiles) SetID(userName string, userProfileID int64) { p.mx.RLock() _, ok := p.idByName[userName] p.mx.RUnlock() @@ -86,11 +90,3 @@ func (p *Profiles) SetID(userName string, userProfileID int64) { p.idByName[userName] = userProfileID } } - -func GetIDFromContext(ctx context.Context) (int64, error) { - return profile.GeIDFromContext(ctx) -} - -func SetID(userName string, userProfileID int64) { - profile.SetID(userName, userProfileID) -} diff --git a/internal/pkg/service/userprofile/service.go b/internal/pkg/service/userprofile/service.go index 1f1b356..a4672cd 100644 --- a/internal/pkg/service/userprofile/service.go +++ b/internal/pkg/service/userprofile/service.go @@ -1,4 +1,4 @@ -package userprofiles +package userprofile import ( "context" From 991ffdb22f6957cf2f87d4dfed46bf80ff1b6570 Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Tue, 23 Jun 2026 01:59:13 +0300 Subject: [PATCH 5/7] fix check-generate --- internal/pkg/service/userprofile/mock/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/pkg/service/userprofile/mock/service.go b/internal/pkg/service/userprofile/mock/service.go index b48115f..bc3ff80 100644 --- a/internal/pkg/service/userprofile/mock/service.go +++ b/internal/pkg/service/userprofile/mock/service.go @@ -6,8 +6,8 @@ // mockgen -destination=internal/pkg/service/userprofile/mock/service.go github.com/ozontech/seq-ui/internal/pkg/service/userprofile Service // -// Package mock_userprofiles is a generated GoMock package. -package mock_userprofiles +// Package mock_userprofile is a generated GoMock package. +package mock_userprofile import ( context "context" From b516193ad3f604329791bd43603b310dfadca18b Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Tue, 23 Jun 2026 09:51:42 +0300 Subject: [PATCH 6/7] rename up to svc --- internal/api/userprofile/v1/userprofile.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/api/userprofile/v1/userprofile.go b/internal/api/userprofile/v1/userprofile.go index 803a4d2..c74a46a 100644 --- a/internal/api/userprofile/v1/userprofile.go +++ b/internal/api/userprofile/v1/userprofile.go @@ -13,10 +13,10 @@ type UserProfile struct { httpAPI *http_api.API } -func New(up userprofile.Service) *UserProfile { +func New(svc userprofile.Service) *UserProfile { return &UserProfile{ - grpcAPI: grpc_api.New(up), - httpAPI: http_api.New(up), + grpcAPI: grpc_api.New(svc), + httpAPI: http_api.New(svc), } } From 1de476868cc8be065af2d101bfe8ad0711b771a6 Mon Sep 17 00:00:00 2001 From: Sergey Lazarenko Date: Tue, 23 Jun 2026 10:21:22 +0300 Subject: [PATCH 7/7] some refactor --- .../api/seqapi/v1/grpc/aggregation_test.go | 17 ++-- .../api/seqapi/v1/grpc/cluster_status_test.go | 16 ++-- internal/api/seqapi/v1/grpc/events_test.go | 6 +- .../v1/grpc/fetch_async_search_result_test.go | 26 +++--- .../v1/grpc/get_async_searches_list_test.go | 34 +++---- internal/api/seqapi/v1/grpc/histogram_test.go | 5 +- .../api/seqapi/v1/grpc/logs_lifespan_test.go | 6 +- internal/api/seqapi/v1/grpc/search_test.go | 23 ++--- .../seqapi/v1/grpc/start_async_search_test.go | 8 +- internal/api/seqapi/v1/grpc/test_data.go | 4 +- .../api/seqapi/v1/http/aggregation_test.go | 45 +++++----- .../api/seqapi/v1/http/aggregation_ts_test.go | 52 +++++------ .../api/seqapi/v1/http/cluster_status_test.go | 8 +- internal/api/seqapi/v1/http/events_test.go | 8 +- internal/api/seqapi/v1/http/export_test.go | 37 ++++---- .../v1/http/fetch_async_search_result_test.go | 60 ++++++------- .../v1/http/get_async_searches_list_test.go | 84 ++++++++--------- internal/api/seqapi/v1/http/histogram_test.go | 25 +++--- .../api/seqapi/v1/http/logs_lifespan_test.go | 6 +- internal/api/seqapi/v1/http/search_test.go | 90 +++++++++---------- .../seqapi/v1/http/start_async_search_test.go | 16 ++-- internal/api/seqapi/v1/http/test_data.go | 4 +- internal/pkg/service/profiles/profiles.go | 12 +-- 23 files changed, 297 insertions(+), 295 deletions(-) diff --git a/internal/api/seqapi/v1/grpc/aggregation_test.go b/internal/api/seqapi/v1/grpc/aggregation_test.go index 230604f..785a824 100644 --- a/internal/api/seqapi/v1/grpc/aggregation_test.go +++ b/internal/api/seqapi/v1/grpc/aggregation_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -35,8 +36,8 @@ func TestGetAggregation(t *testing.T) { name: "ok_multi_agg", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test1"}, {Field: "test2"}, @@ -74,8 +75,8 @@ func TestGetAggregation(t *testing.T) { name: "err_client", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test2"}, }, @@ -145,8 +146,8 @@ func TestGetAggregationWithNormalization(t *testing.T) { name: "ok_count", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, {Field: "test2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, @@ -186,8 +187,8 @@ func TestGetAggregationWithNormalization(t *testing.T) { name: "ok_normalize_count", req: &seqapi.GetAggregationRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval, TargetBucketRate: &targetBucketRate}, {Field: "test2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval, TargetBucketRate: &targetBucketRate}, diff --git a/internal/api/seqapi/v1/grpc/cluster_status_test.go b/internal/api/seqapi/v1/grpc/cluster_status_test.go index 4c70c77..e7bb0b2 100644 --- a/internal/api/seqapi/v1/grpc/cluster_status_test.go +++ b/internal/api/seqapi/v1/grpc/cluster_status_test.go @@ -35,38 +35,38 @@ func TestStatus(t *testing.T) { name: "ok", want: &seqapi.StatusResponse{ NumberOfStores: 3, - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), Stores: []*seqapi.StoreStatus{ { Host: "host-0", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment)}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp)}, }, { Host: "host-1", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(1 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp.Add(1 * time.Hour))}, }, { Host: "host-2", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(2 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp.Add(2 * time.Hour))}, }, }, }, mockArgs: &mockArgs{ resp: &seqapi.StatusResponse{ NumberOfStores: 3, - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), Stores: []*seqapi.StoreStatus{ { Host: "host-0", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment)}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp)}, }, { Host: "host-1", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(1 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp.Add(1 * time.Hour))}, }, { Host: "host-2", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment.Add(2 * time.Hour))}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp.Add(2 * time.Hour))}, }, }, }, diff --git a/internal/api/seqapi/v1/grpc/events_test.go b/internal/api/seqapi/v1/grpc/events_test.go index 17cd3f9..3f10c1f 100644 --- a/internal/api/seqapi/v1/grpc/events_test.go +++ b/internal/api/seqapi/v1/grpc/events_test.go @@ -27,9 +27,9 @@ func TestGetEvent(t *testing.T) { id3 = "test3" id4 = "test4" ) - event1 := test.MakeEvent(id1, 1, testSomeMoment) + event1 := test.MakeEvent(id1, 1, testTimestamp) event1json, _ := proto.Marshal(event1) - event2 := test.MakeEvent(id2, 2, testSomeMoment) + event2 := test.MakeEvent(id2, 2, testTimestamp) event2json, _ := proto.Marshal(event2) event3 := &seqapi.Event{} event3json, _ := proto.Marshal(event3) @@ -339,7 +339,7 @@ func TestGetEventWithMasking(t *testing.T) { Data: map[string]string{ eventField: eventVal, }, - Time: timestamppb.New(testSomeMoment), + Time: timestamppb.New(testTimestamp), } if shouldMask { event.Data[eventField] = "***" diff --git a/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go b/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go index 162cf2c..fe6ad7d 100644 --- a/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go +++ b/internal/api/seqapi/v1/grpc/fetch_async_search_result_test.go @@ -49,8 +49,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -74,7 +74,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -83,7 +83,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-2 * time.Minute)), }, }, Total: 2, @@ -107,14 +107,14 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Value: pointerTo(2), NotExists: 0, Quantiles: []float64{2, 1}, - Ts: timestamppb.New(testSomeMoment), + Ts: timestamppb.New(testTimestamp), }, { Key: "2", Value: pointerTo(8), NotExists: 1, Quantiles: []float64{7, 4}, - Ts: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Ts: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -125,8 +125,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Meta: meta, @@ -153,8 +153,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, @@ -167,7 +167,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, }, Total: 1, @@ -175,8 +175,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Code: seqapi.ErrorCode_ERROR_CODE_NO, }, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Meta: meta, diff --git a/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go b/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go index 62302ef..88d4237 100644 --- a/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go +++ b/internal/api/seqapi/v1/grpc/get_async_searches_list_test.go @@ -50,13 +50,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -68,8 +68,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(testSomeMoment.Add(-1 * time.Hour)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-1 * time.Hour)), + To: timestamppb.New(testTimestamp), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -82,9 +82,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(300 * time.Second)), - CanceledAt: timestamppb.New(testSomeMoment), + StartedAt: timestamppb.New(testTimestamp.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(300 * time.Second)), + CanceledAt: timestamppb.New(testTimestamp), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -111,13 +111,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -144,13 +144,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, diff --git a/internal/api/seqapi/v1/grpc/histogram_test.go b/internal/api/seqapi/v1/grpc/histogram_test.go index 9e10f9e..8b4d25b 100644 --- a/internal/api/seqapi/v1/grpc/histogram_test.go +++ b/internal/api/seqapi/v1/grpc/histogram_test.go @@ -3,6 +3,7 @@ package grpc import ( "context" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -31,8 +32,8 @@ func TestGetHistogram(t *testing.T) { name: "ok", req: &seqapi.GetHistogramRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Interval: interval, }, want: &seqapi.GetHistogramResponse{ diff --git a/internal/api/seqapi/v1/grpc/logs_lifespan_test.go b/internal/api/seqapi/v1/grpc/logs_lifespan_test.go index 55570ce..9b2fc2f 100644 --- a/internal/api/seqapi/v1/grpc/logs_lifespan_test.go +++ b/internal/api/seqapi/v1/grpc/logs_lifespan_test.go @@ -61,7 +61,7 @@ func TestGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), }, resp: &seqapi.GetLogsLifespanResponse{ Lifespan: durationpb.New(result), @@ -76,7 +76,7 @@ func TestGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), }, resp: &seqapi.GetLogsLifespanResponse{ Lifespan: durationpb.New(result), @@ -140,7 +140,7 @@ func TestGetLogsLifespan(t *testing.T) { s := setupTestAPI(seqData) s.nowFn = func() time.Time { - return testSomeMoment.Add(result) + return testTimestamp.Add(result) } resp, err := s.GetLogsLifespan(context.Background(), nil) diff --git a/internal/api/seqapi/v1/grpc/search_test.go b/internal/api/seqapi/v1/grpc/search_test.go index 8523e2e..b818531 100644 --- a/internal/api/seqapi/v1/grpc/search_test.go +++ b/internal/api/seqapi/v1/grpc/search_test.go @@ -3,6 +3,7 @@ package grpc import ( "context" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -37,8 +38,8 @@ func TestSearch(t *testing.T) { name: "ok", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: limit, Offset: 0, WithTotal: true, @@ -52,7 +53,7 @@ func TestSearch(t *testing.T) { Order: seqapi.Order_ORDER_ASC, }, resp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), testSomeMoment), + Events: test.MakeEvents(int(limit), testTimestamp), Total: int64(limit), Histogram: test.MakeHistogram(2), Aggregations: test.MakeAggregations(2, 2, nil), @@ -108,8 +109,8 @@ func TestSearch(t *testing.T) { name: "err_offset_too_high", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: limit, Offset: 11, }, @@ -125,18 +126,18 @@ func TestSearch(t *testing.T) { name: "err_total_too_high", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: limit, Offset: 0, WithTotal: true, }, resp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), testSomeMoment), + Events: test.MakeEvents(int(limit), testTimestamp), Total: int64(limit) + 1, }, wantResp: &seqapi.SearchResponse{ - Events: test.MakeEvents(int(limit), testSomeMoment), + Events: test.MakeEvents(int(limit), testTimestamp), Total: int64(limit) + 1, Error: &seqapi.Error{ Code: seqapi.ErrorCode_ERROR_CODE_QUERY_TOO_HEAVY, @@ -154,8 +155,8 @@ func TestSearch(t *testing.T) { name: "err_client", req: &seqapi.SearchRequest{ Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: limit, Offset: 0, }, diff --git a/internal/api/seqapi/v1/grpc/start_async_search_test.go b/internal/api/seqapi/v1/grpc/start_async_search_test.go index 688b5be..03cbc21 100644 --- a/internal/api/seqapi/v1/grpc/start_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/start_async_search_test.go @@ -42,8 +42,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ @@ -73,8 +73,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: query, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ diff --git a/internal/api/seqapi/v1/grpc/test_data.go b/internal/api/seqapi/v1/grpc/test_data.go index 3fdd0ff..a088897 100644 --- a/internal/api/seqapi/v1/grpc/test_data.go +++ b/internal/api/seqapi/v1/grpc/test_data.go @@ -14,9 +14,7 @@ import ( var ( errSomethingWrong = errors.New("something happened wrong") testSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" - testSomeMoment = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - testFrom = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - testTo = testFrom.Add(time.Second) + testTimestamp = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) ) func setupTestAPI(data test.APITestData) *API { diff --git a/internal/api/seqapi/v1/http/aggregation_test.go b/internal/api/seqapi/v1/http/aggregation_test.go index f95425b..6a675f4 100644 --- a/internal/api/seqapi/v1/http/aggregation_test.go +++ b/internal/api/seqapi/v1/http/aggregation_test.go @@ -4,6 +4,7 @@ import ( "errors" "net/http" "testing" + "time" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -36,15 +37,15 @@ func TestServeGetAggregation(t *testing.T) { name: "ok_single_agg", req: getAggregationRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), AggField: "test_single", }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), AggField: "test_single", }, resp: &seqapi.GetAggregationResponse{ @@ -71,8 +72,8 @@ func TestServeGetAggregation(t *testing.T) { name: "ok_multi_agg", req: getAggregationRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Aggregations: aggregationQueries{ {Field: "test_multi1"}, {Field: "test_multi2"}, @@ -82,8 +83,8 @@ func TestServeGetAggregation(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test_multi1"}, {Field: "test_multi2"}, @@ -115,8 +116,8 @@ func TestServeGetAggregation(t *testing.T) { name: "ok_agg_quantile", req: getAggregationRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Aggregations: aggregationQueries{ { Field: "test_multi1", @@ -129,8 +130,8 @@ func TestServeGetAggregation(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ { Field: "test_multi1", @@ -176,15 +177,15 @@ func TestServeGetAggregation(t *testing.T) { name: "err_partial_response", req: getAggregationRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), AggField: "test_err_partial", }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), AggField: "test_err_partial", }, resp: &seqapi.GetAggregationResponse{ @@ -211,8 +212,8 @@ func TestServeGetAggregation(t *testing.T) { name: "err_aggs_limit_max", req: getAggregationRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Aggregations: aggregationQueries{{}, {}, {}}, }, wantErr: true, @@ -226,15 +227,15 @@ func TestServeGetAggregation(t *testing.T) { name: "err_client", req: getAggregationRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), AggField: "test_err_client", }, mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), AggField: "test_err_client", }, err: errors.New("client error"), diff --git a/internal/api/seqapi/v1/http/aggregation_ts_test.go b/internal/api/seqapi/v1/http/aggregation_ts_test.go index d911dff..9c4f86c 100644 --- a/internal/api/seqapi/v1/http/aggregation_ts_test.go +++ b/internal/api/seqapi/v1/http/aggregation_ts_test.go @@ -31,7 +31,7 @@ func TestServeGetAggregationTs(t *testing.T) { aggQueriesRaw, err := json.Marshal(aggQueries) assert.NoError(t, err) return fmt.Sprintf(`{"query":%q,"from":%q,"to":%q,"aggregations":%s}`, - testQuery, testFrom.Format(time.RFC3339), testTo.Format(time.RFC3339), aggQueriesRaw) + testQuery, testTimestamp.Format(time.RFC3339), testTimestamp.Add(time.Second).Format(time.RFC3339), aggQueriesRaw) } type mockArgs struct { @@ -71,8 +71,8 @@ func TestServeGetAggregationTs(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test_count1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, {Field: "test_count2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval}, @@ -81,9 +81,9 @@ func TestServeGetAggregationTs(t *testing.T) { resp: &seqapi.GetAggregationResponse{ Aggregation: test.MakeAggregation(3, &test.MakeAggOpts{ Ts: []*timestamppb.Timestamp{ - timestamppb.New(testFrom.Add(time.Second)), - timestamppb.New(testFrom.Add(2 * time.Second)), - timestamppb.New(testFrom.Add(3 * time.Second)), + timestamppb.New(testTimestamp.Add(time.Second)), + timestamppb.New(testTimestamp.Add(2 * time.Second)), + timestamppb.New(testTimestamp.Add(3 * time.Second)), }, Values: []float64{ 1, @@ -93,9 +93,9 @@ func TestServeGetAggregationTs(t *testing.T) { }), Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ Ts: []*timestamppb.Timestamp{ - timestamppb.New(testFrom.Add(time.Second)), - timestamppb.New(testFrom.Add(2 * time.Second)), - timestamppb.New(testFrom.Add(3 * time.Second)), + timestamppb.New(testTimestamp.Add(time.Second)), + timestamppb.New(testTimestamp.Add(2 * time.Second)), + timestamppb.New(testTimestamp.Add(3 * time.Second)), }, }), Error: &seqapi.Error{ @@ -134,8 +134,8 @@ func TestServeGetAggregationTs(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ {Field: "test_count1", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval2}, {Field: "test_count2", Func: seqapi.AggFunc_AGG_FUNC_COUNT, Interval: &interval2, TargetBucketRate: &targetBucketRate}, @@ -144,9 +144,9 @@ func TestServeGetAggregationTs(t *testing.T) { resp: &seqapi.GetAggregationResponse{ Aggregations: test.MakeAggregations(2, 3, &test.MakeAggOpts{ Ts: []*timestamppb.Timestamp{ - timestamppb.New(testFrom.Add(time.Second)), - timestamppb.New(testFrom.Add(2 * time.Second)), - timestamppb.New(testFrom.Add(3 * time.Second)), + timestamppb.New(testTimestamp.Add(time.Second)), + timestamppb.New(testTimestamp.Add(2 * time.Second)), + timestamppb.New(testTimestamp.Add(3 * time.Second)), }, Values: []float64{ 3, @@ -184,8 +184,8 @@ func TestServeGetAggregationTs(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Aggregations: []*seqapi.AggregationQuery{ { Field: "test_quantile1", @@ -200,17 +200,17 @@ func TestServeGetAggregationTs(t *testing.T) { Aggregation: test.MakeAggregation(3, &test.MakeAggOpts{ Quantiles: []float64{100, 150}, Ts: []*timestamppb.Timestamp{ - timestamppb.New(testFrom.Add(time.Second)), - timestamppb.New(testFrom.Add(2 * time.Second)), - timestamppb.New(testFrom.Add(3 * time.Second)), + timestamppb.New(testTimestamp.Add(time.Second)), + timestamppb.New(testTimestamp.Add(2 * time.Second)), + timestamppb.New(testTimestamp.Add(3 * time.Second)), }, }), Aggregations: test.MakeAggregations(1, 3, &test.MakeAggOpts{ Quantiles: []float64{100, 150}, Ts: []*timestamppb.Timestamp{ - timestamppb.New(testFrom.Add(time.Second)), - timestamppb.New(testFrom.Add(2 * time.Second)), - timestamppb.New(testFrom.Add(3 * time.Second)), + timestamppb.New(testTimestamp.Add(time.Second)), + timestamppb.New(testTimestamp.Add(2 * time.Second)), + timestamppb.New(testTimestamp.Add(3 * time.Second)), }, }), Error: &seqapi.Error{ @@ -233,8 +233,8 @@ func TestServeGetAggregationTs(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), }, resp: &seqapi.GetAggregationResponse{ Error: &seqapi.Error{ @@ -290,8 +290,8 @@ func TestServeGetAggregationTs(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetAggregationRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), }, err: errors.New("client error"), }, diff --git a/internal/api/seqapi/v1/http/cluster_status_test.go b/internal/api/seqapi/v1/http/cluster_status_test.go index 8d90ebb..0151beb 100644 --- a/internal/api/seqapi/v1/http/cluster_status_test.go +++ b/internal/api/seqapi/v1/http/cluster_status_test.go @@ -30,23 +30,23 @@ func TestStatus(t *testing.T) { { name: "ok", want: statusResponse{ - OldestStorageTime: &testSomeMoment, + OldestStorageTime: &testTimestamp, NumberOfStores: 1, Stores: []storeStatus{ { Host: "host-0", - Values: &storeStatusValues{OldestTime: &testSomeMoment}, + Values: &storeStatusValues{OldestTime: &testTimestamp}, }, }, }, mockArgs: &mockArgs{ resp: &seqapi.StatusResponse{ NumberOfStores: 1, - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), Stores: []*seqapi.StoreStatus{ { Host: "host-0", - Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testSomeMoment)}, + Values: &seqapi.StoreStatusValues{OldestTime: timestamppb.New(testTimestamp)}, }, }, }, diff --git a/internal/api/seqapi/v1/http/events_test.go b/internal/api/seqapi/v1/http/events_test.go index 372ece9..7b33966 100644 --- a/internal/api/seqapi/v1/http/events_test.go +++ b/internal/api/seqapi/v1/http/events_test.go @@ -29,11 +29,11 @@ func TestServeGetEvent(t *testing.T) { cacheTTL = time.Minute ) - event1 := test.MakeEvent(id1, 1, testSomeMoment) + event1 := test.MakeEvent(id1, 1, testTimestamp) event1json, _ := proto.Marshal(event1) - event2 := test.MakeEvent(id2, 2, testSomeMoment) + event2 := test.MakeEvent(id2, 2, testTimestamp) event2json, _ := proto.Marshal(event2) - event3 := test.MakeEvent(id3, 0, testSomeMoment) + event3 := test.MakeEvent(id3, 0, testTimestamp) event3json, _ := proto.Marshal(event3) type mockArgs struct { @@ -351,7 +351,7 @@ func TestGetEventWithMasking(t *testing.T) { Data: map[string]string{ eventField: eventVal, }, - Time: timestamppb.New(testSomeMoment), + Time: timestamppb.New(testTimestamp), } if shouldMask { event.Data[eventField] = "***" diff --git a/internal/api/seqapi/v1/http/export_test.go b/internal/api/seqapi/v1/http/export_test.go index 3b8fb63..d203aa3 100644 --- a/internal/api/seqapi/v1/http/export_test.go +++ b/internal/api/seqapi/v1/http/export_test.go @@ -3,6 +3,7 @@ package http import ( "net/http" "testing" + "time" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -33,8 +34,8 @@ func TestServeExport(t *testing.T) { name: "ok_jsonl", req: exportRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 50, Offset: 0, }, @@ -47,8 +48,8 @@ func TestServeExport(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 50, Offset: 0, }, @@ -58,8 +59,8 @@ func TestServeExport(t *testing.T) { name: "ok_csv", req: exportRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 50, Offset: 0, Format: efCSV, @@ -74,8 +75,8 @@ func TestServeExport(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 50, Offset: 0, Format: seqapi.ExportFormat_EXPORT_FORMAT_CSV, @@ -87,8 +88,8 @@ func TestServeExport(t *testing.T) { name: "err_parallel_limited", req: exportRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 0, Offset: 0, }, @@ -103,8 +104,8 @@ func TestServeExport(t *testing.T) { name: "err_export_limit_max", req: exportRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 10, Offset: 0, }, @@ -120,8 +121,8 @@ func TestServeExport(t *testing.T) { name: "err_csv_empty_fields", req: exportRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 10, Offset: 0, Format: efCSV, @@ -138,8 +139,8 @@ func TestServeExport(t *testing.T) { name: "err_client", req: exportRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 50, Offset: 0, }, @@ -153,8 +154,8 @@ func TestServeExport(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.ExportRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 50, Offset: 0, }, diff --git a/internal/api/seqapi/v1/http/fetch_async_search_result_test.go b/internal/api/seqapi/v1/http/fetch_async_search_result_test.go index faaa7fb..95c1175 100644 --- a/internal/api/seqapi/v1/http/fetch_async_search_result_test.go +++ b/internal/api/seqapi/v1/http/fetch_async_search_result_test.go @@ -44,8 +44,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -75,7 +75,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -84,7 +84,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-2 * time.Minute)), }, }, Total: 2, @@ -123,19 +123,19 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Key: "33", Value: pointerTo[float64](2), NotExists: 0, - Ts: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + Ts: timestamppb.New(testTimestamp.Add(-30 * time.Second)), }, { Key: "33", Value: pointerTo[float64](5), NotExists: 0, - Ts: timestamppb.New(testSomeMoment), + Ts: timestamppb.New(testTimestamp), }, { Key: "22", Value: pointerTo[float64](8), NotExists: 1, - Ts: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Ts: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -146,8 +146,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -166,8 +166,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -197,7 +197,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -206,7 +206,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-2 * time.Minute)), }, }, Total: 2, @@ -245,19 +245,19 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Key: "33", Value: pointerTo[float64](2), NotExists: 0, - Ts: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), + Ts: timestamppb.New(testTimestamp.Add(-30 * time.Second)), }, { Key: "33", Value: pointerTo[float64](5), NotExists: 0, - Ts: timestamppb.New(testSomeMoment), + Ts: timestamppb.New(testTimestamp), }, { Key: "22", Value: pointerTo[float64](8), NotExists: 1, - Ts: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Ts: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, }, NotExists: 2, @@ -268,8 +268,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -291,8 +291,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, @@ -305,7 +305,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -314,7 +314,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-2 * time.Minute)), }, }, Total: 2, @@ -323,8 +323,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ @@ -344,8 +344,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, @@ -358,7 +358,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error", "x": "2", }, - Time: timestamppb.New(testSomeMoment.Add(-1 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-1 * time.Minute)), }, { Id: "017a854298010000-8502fe7f2aa33df3", @@ -367,7 +367,7 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { "message": "some error 2", "x": "8", }, - Time: timestamppb.New(testSomeMoment.Add(-2 * time.Minute)), + Time: timestamppb.New(testTimestamp.Add(-2 * time.Minute)), }, }, Total: 2, @@ -376,8 +376,8 @@ func TestServeFetchAsyncSearchResult(t *testing.T) { Message: "some error", }, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, Error: &seqapi.Error{ diff --git a/internal/api/seqapi/v1/http/get_async_searches_list_test.go b/internal/api/seqapi/v1/http/get_async_searches_list_test.go index d8fbcd8..5934a98 100644 --- a/internal/api/seqapi/v1/http/get_async_searches_list_test.go +++ b/internal/api/seqapi/v1/http/get_async_searches_list_test.go @@ -50,13 +50,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -68,8 +68,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(testSomeMoment.Add(-1 * time.Hour)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-1 * time.Hour)), + To: timestamppb.New(testTimestamp), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -83,9 +83,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(300 * time.Second)), - CanceledAt: timestamppb.New(testSomeMoment), + StartedAt: timestamppb.New(testTimestamp.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(300 * time.Second)), + CanceledAt: timestamppb.New(testTimestamp), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -105,13 +105,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -123,8 +123,8 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(360 * time.Second), Query: "message:error and level:3", - From: timestamppb.New(testSomeMoment.Add(-1 * time.Hour)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-1 * time.Hour)), + To: timestamppb.New(testTimestamp), Aggs: []*seqapi.AggregationQuery{ { Field: "x", @@ -138,9 +138,9 @@ func TestServeGetAsyncSearchesList(t *testing.T) { }, WithDocs: false, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-60 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(300 * time.Second)), - CanceledAt: timestamppb.New(testSomeMoment), + StartedAt: timestamppb.New(testTimestamp.Add(-60 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(300 * time.Second)), + CanceledAt: timestamppb.New(testTimestamp), Progress: 1, DiskUsage: 256, OwnerName: mockUserName2, @@ -168,13 +168,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -199,13 +199,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -228,13 +228,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -255,13 +255,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: "message:error", - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -301,13 +301,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: tooLongQuery, - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, @@ -328,13 +328,13 @@ func TestServeGetAsyncSearchesList(t *testing.T) { Request: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: tooLongQuery, - From: timestamppb.New(testSomeMoment.Add(-15 * time.Minute)), - To: timestamppb.New(testSomeMoment), + From: timestamppb.New(testTimestamp.Add(-15 * time.Minute)), + To: timestamppb.New(testTimestamp), WithDocs: true, Size: 100, }, - StartedAt: timestamppb.New(testSomeMoment.Add(-30 * time.Second)), - ExpiresAt: timestamppb.New(testSomeMoment.Add(30 * time.Second)), + StartedAt: timestamppb.New(testTimestamp.Add(-30 * time.Second)), + ExpiresAt: timestamppb.New(testTimestamp.Add(30 * time.Second)), Progress: 1, DiskUsage: 512, OwnerName: mockUserName1, diff --git a/internal/api/seqapi/v1/http/histogram_test.go b/internal/api/seqapi/v1/http/histogram_test.go index 814d0b8..e0efedb 100644 --- a/internal/api/seqapi/v1/http/histogram_test.go +++ b/internal/api/seqapi/v1/http/histogram_test.go @@ -4,6 +4,7 @@ import ( "errors" "net/http" "testing" + "time" "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" @@ -34,8 +35,8 @@ func TestServeGetHistogram(t *testing.T) { name: "ok", req: getHistogramRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Interval: "5s", }, want: getHistogramResponse{ @@ -51,8 +52,8 @@ func TestServeGetHistogram(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Interval: "5s", }, resp: &seqapi.GetHistogramResponse{ @@ -67,8 +68,8 @@ func TestServeGetHistogram(t *testing.T) { name: "err_partial_response", req: getHistogramRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Interval: "10s", }, want: getHistogramResponse{ @@ -81,8 +82,8 @@ func TestServeGetHistogram(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Interval: "10s", }, resp: &seqapi.GetHistogramResponse{ @@ -98,16 +99,16 @@ func TestServeGetHistogram(t *testing.T) { name: "err_client", req: getHistogramRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Interval: "20s", }, wantErr: true, mockArgs: &mockArgs{ req: &seqapi.GetHistogramRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Interval: "20s", }, err: errors.New("client error"), diff --git a/internal/api/seqapi/v1/http/logs_lifespan_test.go b/internal/api/seqapi/v1/http/logs_lifespan_test.go index 13ef59e..0ed4b5c 100644 --- a/internal/api/seqapi/v1/http/logs_lifespan_test.go +++ b/internal/api/seqapi/v1/http/logs_lifespan_test.go @@ -60,7 +60,7 @@ func TestServeGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), }, want: getLogsLifespanResponse{Lifespan: 36000}, }, @@ -73,7 +73,7 @@ func TestServeGetLogsLifespan(t *testing.T) { Value: resultStr, }, clientResp: &seqapi.StatusResponse{ - OldestStorageTime: timestamppb.New(testSomeMoment), + OldestStorageTime: timestamppb.New(testTimestamp), }, want: getLogsLifespanResponse{Lifespan: 36000}, }, @@ -137,7 +137,7 @@ func TestServeGetLogsLifespan(t *testing.T) { api := setupTestAPI(seqData) api.nowFn = func() time.Time { - return testSomeMoment.Add(result) + return testTimestamp.Add(result) } httputil.DoTestHTTPEx(t, httputil.TestDataHTTPEx[struct{}, getLogsLifespanResponse]{ diff --git a/internal/api/seqapi/v1/http/search_test.go b/internal/api/seqapi/v1/http/search_test.go index c59c25b..c22272f 100644 --- a/internal/api/seqapi/v1/http/search_test.go +++ b/internal/api/seqapi/v1/http/search_test.go @@ -18,7 +18,7 @@ import ( func TestServeSearch(t *testing.T) { var ( - eventTime = testFrom.Add(time.Millisecond) + eventTime = testTimestamp.Add(time.Millisecond) ) type mockArgs struct { @@ -41,8 +41,8 @@ func TestServeSearch(t *testing.T) { name: "ok_simple", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, }, want: searchResponse{ @@ -58,8 +58,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, }, @@ -75,8 +75,8 @@ func TestServeSearch(t *testing.T) { name: "ok_with_total", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, WithTotal: true, }, @@ -94,8 +94,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, WithTotal: true, @@ -113,8 +113,8 @@ func TestServeSearch(t *testing.T) { name: "ok_order_asc", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, Order: oASC, }, @@ -131,8 +131,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, Order: seqapi.Order_ORDER_ASC, @@ -149,8 +149,8 @@ func TestServeSearch(t *testing.T) { name: "ok_with_hist", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, Histogram: struct { Interval string "json:\"interval\"" @@ -170,8 +170,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, Histogram: &seqapi.SearchRequest_Histogram{ @@ -191,8 +191,8 @@ func TestServeSearch(t *testing.T) { name: "ok_with_aggs", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, Aggregations: aggregationQueries{ { @@ -218,8 +218,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, Aggregations: []*seqapi.AggregationQuery{ @@ -245,8 +245,8 @@ func TestServeSearch(t *testing.T) { name: "ok_empty_events", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, }, want: searchResponse{ @@ -262,8 +262,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, }, @@ -279,8 +279,8 @@ func TestServeSearch(t *testing.T) { name: "err_partial_response", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, }, want: searchResponse{ @@ -296,8 +296,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, }, @@ -315,8 +315,8 @@ func TestServeSearch(t *testing.T) { name: "err_search_limit_zero", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 0, }, wantErr: true, @@ -325,8 +325,8 @@ func TestServeSearch(t *testing.T) { name: "err_search_limit_max", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 10, }, cfg: config.SeqAPI{ @@ -340,8 +340,8 @@ func TestServeSearch(t *testing.T) { name: "err_aggs_limit_max", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, Aggregations: aggregationQueries{{}, {}, {}}, }, @@ -357,8 +357,8 @@ func TestServeSearch(t *testing.T) { name: "err_offset_too_high", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, Offset: 11, }, @@ -374,8 +374,8 @@ func TestServeSearch(t *testing.T) { name: "err_total_too_high", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, WithTotal: true, }, @@ -394,8 +394,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, WithTotal: true, @@ -414,8 +414,8 @@ func TestServeSearch(t *testing.T) { name: "err_client", req: searchRequest{ Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), Limit: 3, }, cfg: test.SetCfgDefaults(config.SeqAPI{ @@ -427,8 +427,8 @@ func TestServeSearch(t *testing.T) { mockArgs: &mockArgs{ req: &seqapi.SearchRequest{ Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), Limit: 3, Offset: 0, }, diff --git a/internal/api/seqapi/v1/http/start_async_search_test.go b/internal/api/seqapi/v1/http/start_async_search_test.go index 0797b54..8541d72 100644 --- a/internal/api/seqapi/v1/http/start_async_search_test.go +++ b/internal/api/seqapi/v1/http/start_async_search_test.go @@ -40,8 +40,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: startAsyncSearchRequest{ Retention: "60s", Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), WithDocs: true, Size: 100, Meta: meta, @@ -67,8 +67,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ @@ -95,8 +95,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: startAsyncSearchRequest{ Retention: "60s", Query: testQuery, - From: testFrom, - To: testTo, + From: testTimestamp, + To: testTimestamp.Add(time.Second), WithDocs: true, Size: 100, Meta: meta, @@ -120,8 +120,8 @@ func TestServeStartAsyncSearch(t *testing.T) { req: &seqapi.StartAsyncSearchRequest{ Retention: durationpb.New(60 * time.Second), Query: testQuery, - From: timestamppb.New(testFrom), - To: timestamppb.New(testTo), + From: timestamppb.New(testTimestamp), + To: timestamppb.New(testTimestamp.Add(time.Second)), WithDocs: true, Size: 100, Hist: &seqapi.StartAsyncSearchRequest_HistQuery{ diff --git a/internal/api/seqapi/v1/http/test_data.go b/internal/api/seqapi/v1/http/test_data.go index 6135d38..0f24d93 100644 --- a/internal/api/seqapi/v1/http/test_data.go +++ b/internal/api/seqapi/v1/http/test_data.go @@ -19,9 +19,7 @@ var ( errSomethingWrong = errors.New("something happened wrong") testSearchID = "69e4a4a6-0922-43bd-952d-060a86c2b622" testQuery = "message:error" - testFrom = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) - testTo = testFrom.Add(time.Second) - testSomeMoment = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) + testTimestamp = time.Date(2023, time.September, 25, 10, 20, 30, 0, time.UTC) ) func setupTestAPI(data test.APITestData) *API { diff --git a/internal/pkg/service/profiles/profiles.go b/internal/pkg/service/profiles/profiles.go index 91c66fe..829bf4a 100644 --- a/internal/pkg/service/profiles/profiles.go +++ b/internal/pkg/service/profiles/profiles.go @@ -28,20 +28,20 @@ type profiles struct { } func GetIDFromContext(ctx context.Context) (int64, error) { - return profile.GeIDFromContext(ctx) + return profile.getIDFromContext(ctx) } func SetID(userName string, userProfileID int64) { - profile.SetID(userName, userProfileID) + profile.setID(userName, userProfileID) } -func (p *profiles) GeIDFromContext(ctx context.Context) (int64, error) { +func (p *profiles) getIDFromContext(ctx context.Context) (int64, error) { userName, err := types.GetUserKey(ctx) if err != nil { return 0, err } - id, err := p.GetID(userName) + id, err := p.getID(userName) if err != nil { return 0, err } @@ -49,7 +49,7 @@ func (p *profiles) GeIDFromContext(ctx context.Context) (int64, error) { return id, nil } -func (p *profiles) GetID(userName string) (int64, error) { +func (p *profiles) getID(userName string) (int64, error) { p.mx.RLock() id, ok := p.idByName[userName] p.mx.RUnlock() @@ -75,7 +75,7 @@ func (p *profiles) GetID(userName string) (int64, error) { return id, nil } -func (p *profiles) SetID(userName string, userProfileID int64) { +func (p *profiles) setID(userName string, userProfileID int64) { p.mx.RLock() _, ok := p.idByName[userName] p.mx.RUnlock()