From d477a14a9d8f59b9842a13a39f6cfa3c8a2a248b Mon Sep 17 00:00:00 2001 From: lifosmin <65651883+lifosmin@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:57:26 +0700 Subject: [PATCH 1/2] feat: Search and Filter for ListAppeals and ListGrants (#62) * feat: Add filter q, account_type for litAppeals and listGrants and added getTotalCount * chore: added testing for total count * chore: fix testing * chore: fix test total * chore: fix test mock appeal and grant * chore: fix test mock user appeal and grant * chore: fix test coverage * chore: fix test coverage 2 * chore: fix test coverage 3 * chore: resolve comments * test: resolve comments * test: fix testing --------- Co-authored-by: Lifosmin Simon --- api/handler/v1beta1/appeal.go | 47 ++++- api/handler/v1beta1/appeal_test.go | 32 +++- api/handler/v1beta1/grant.go | 40 ++++- api/handler/v1beta1/grant_test.go | 17 +- api/handler/v1beta1/grpc.go | 2 + api/handler/v1beta1/mocks/activityService.go | 58 ++++-- api/handler/v1beta1/mocks/appealService.go | 165 ++++++++++++++---- api/handler/v1beta1/mocks/approvalService.go | 11 +- api/handler/v1beta1/mocks/grantService.go | 64 ++++++- api/handler/v1beta1/mocks/policyService.go | 62 +++++-- api/handler/v1beta1/mocks/providerService.go | 151 ++++++++++++---- api/handler/v1beta1/mocks/resourceService.go | 94 ++++++++-- buf.gen.yaml | 4 +- core/appeal/mocks/approvalService.go | 31 ++-- core/appeal/mocks/auditLogger.go | 27 ++- core/appeal/mocks/grantService.go | 64 +++++-- core/appeal/mocks/iamManager.go | 40 ++++- core/appeal/mocks/notifier.go | 23 ++- core/appeal/mocks/policyService.go | 44 ++++- core/appeal/mocks/providerService.go | 77 ++++++-- core/appeal/mocks/repository.go | 115 ++++++++++-- core/appeal/mocks/resourceService.go | 44 ++++- core/appeal/service.go | 5 + core/appeal/service_test.go | 26 +++ core/grant/mocks/auditLogger.go | 27 ++- core/grant/mocks/notifier.go | 23 ++- core/grant/mocks/providerService.go | 11 +- core/grant/mocks/repository.go | 115 ++++++++++-- core/grant/mocks/resourceService.go | 30 +++- core/grant/service.go | 5 + core/grant/service_test.go | 26 +++ domain/appeal.go | 2 + domain/grant.go | 5 +- internal/store/postgres/appeal_repository.go | 142 +++++++++------ .../store/postgres/appeal_repository_test.go | 77 +++++++- .../postgres/approval_repository_test.go | 8 + internal/store/postgres/grant_repository.go | 142 ++++++++------- .../store/postgres/grant_repository_test.go | 23 +++ 38 files changed, 1520 insertions(+), 359 deletions(-) diff --git a/api/handler/v1beta1/appeal.go b/api/handler/v1beta1/appeal.go index 524c29677..b96f5513f 100644 --- a/api/handler/v1beta1/appeal.go +++ b/api/handler/v1beta1/appeal.go @@ -7,6 +7,7 @@ import ( guardianv1beta1 "github.com/goto/guardian/api/proto/gotocompany/guardian/v1beta1" "github.com/goto/guardian/core/appeal" "github.com/goto/guardian/domain" + "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -35,27 +36,36 @@ func (s *GRPCServer) ListUserAppeals(ctx context.Context, req *guardianv1beta1.L if req.GetResourceTypes() != nil { filters.ResourceTypes = req.GetResourceTypes() } + if req.GetAccountTypes() != nil { + filters.AccountTypes = req.GetAccountTypes() + } if req.GetResourceUrns() != nil { filters.ResourceURNs = req.GetResourceUrns() } if req.GetOrderBy() != nil { filters.OrderBy = req.GetOrderBy() } + if req.GetQ() != "" { + filters.Q = req.GetQ() + } filters.Offset = int(req.GetOffset()) filters.Size = int(req.GetSize()) - appeals, err := s.listAppeals(ctx, filters) + appeals, total, err := s.listAppeals(ctx, filters) if err != nil { return nil, err } return &guardianv1beta1.ListUserAppealsResponse{ Appeals: appeals, + Total: int32(total), }, nil } func (s *GRPCServer) ListAppeals(ctx context.Context, req *guardianv1beta1.ListAppealsRequest) (*guardianv1beta1.ListAppealsResponse, error) { filters := &domain.ListAppealsFilter{ + Q: req.GetQ(), + AccountTypes: req.GetAccountTypes(), AccountID: req.GetAccountId(), Statuses: req.GetStatuses(), Role: req.GetRole(), @@ -67,13 +77,14 @@ func (s *GRPCServer) ListAppeals(ctx context.Context, req *guardianv1beta1.ListA Offset: int(req.GetOffset()), OrderBy: req.GetOrderBy(), } - appeals, err := s.listAppeals(ctx, filters) + appeals, total, err := s.listAppeals(ctx, filters) if err != nil { return nil, err } return &guardianv1beta1.ListAppealsResponse{ Appeals: appeals, + Total: int32(total), }, nil } @@ -166,20 +177,40 @@ func (s *GRPCServer) CancelAppeal(ctx context.Context, req *guardianv1beta1.Canc }, nil } -func (s *GRPCServer) listAppeals(ctx context.Context, filters *domain.ListAppealsFilter) ([]*guardianv1beta1.Appeal, error) { - appeals, err := s.appealService.Find(ctx, filters) - if err != nil { - return nil, status.Errorf(codes.Internal, "failed to get appeal list: %s", err) +func (s *GRPCServer) listAppeals(ctx context.Context, filters *domain.ListAppealsFilter) ([]*guardianv1beta1.Appeal, int64, error) { + eg, ctx := errgroup.WithContext(ctx) + var appeals []*domain.Appeal + var total int64 + + eg.Go(func() error { + appealRecords, err := s.appealService.Find(ctx, filters) + if err != nil { + return status.Errorf(codes.Internal, "failed to get appeal list: %s", err) + } + appeals = appealRecords + return nil + }) + eg.Go(func() error { + totalRecord, err := s.appealService.GetAppealsTotalCount(ctx, filters) + if err != nil { + return status.Errorf(codes.Internal, "failed to get appeal total count: %s", err) + } + total = totalRecord + return nil + }) + + if err := eg.Wait(); err != nil { + return nil, 0, err } appealProtos := []*guardianv1beta1.Appeal{} for _, a := range appeals { appealProto, err := s.adapter.ToAppealProto(a) if err != nil { - return nil, status.Errorf(codes.Internal, "failed to parse appeal: %s", err) + return nil, 0, status.Errorf(codes.Internal, "failed to parse appeal: %s", err) } appealProtos = append(appealProtos, appealProto) } - return appealProtos, nil + return appealProtos, total, nil } diff --git a/api/handler/v1beta1/appeal_test.go b/api/handler/v1beta1/appeal_test.go index bdc9608f7..a419a701c 100644 --- a/api/handler/v1beta1/appeal_test.go +++ b/api/handler/v1beta1/appeal_test.go @@ -3,6 +3,7 @@ package v1beta1_test import ( "context" "errors" + "fmt" "time" "github.com/google/uuid" @@ -33,6 +34,8 @@ func (s *GrpcHandlersSuite) TestListUserAppeals() { ResourceTypes: []string{"test-resource-type"}, ResourceURNs: []string{"test-resource-urn"}, OrderBy: []string{"test-order"}, + AccountTypes: []string{"test-account-type"}, + Q: "test", } expectedAppeals := []*domain.Appeal{ { @@ -117,9 +120,12 @@ func (s *GrpcHandlersSuite) TestListUserAppeals() { UpdatedAt: timestamppb.New(timeNow), }, }, + Total: 1, } - s.appealService.EXPECT().Find(mock.AnythingOfType("*context.valueCtx"), expectedFilters). + s.appealService.EXPECT().Find(mock.AnythingOfType("*context.cancelCtx"), expectedFilters). Return(expectedAppeals, nil).Once() + s.appealService.EXPECT().GetAppealsTotalCount(mock.AnythingOfType("*context.cancelCtx"), expectedFilters). + Return(int64(1), nil).Once() req := &guardianv1beta1.ListUserAppealsRequest{ Statuses: []string{"active", "pending"}, @@ -129,6 +135,8 @@ func (s *GrpcHandlersSuite) TestListUserAppeals() { ResourceTypes: []string{"test-resource-type"}, ResourceUrns: []string{"test-resource-urn"}, OrderBy: []string{"test-order"}, + AccountTypes: []string{"test-account-type"}, + Q: "test", } ctx := context.WithValue(context.Background(), authEmailTestContextKey{}, expectedUser) res, err := s.grpcServer.ListUserAppeals(ctx, req) @@ -156,13 +164,16 @@ func (s *GrpcHandlersSuite) TestListUserAppeals() { s.setup() expectedError := errors.New("random error") - s.appealService.EXPECT().Find(mock.AnythingOfType("*context.valueCtx"), mock.Anything). + s.appealService.EXPECT().Find(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). Return(nil, expectedError).Once() + s.appealService.EXPECT().GetAppealsTotalCount(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). + Return(int64(0), nil).Once() req := &guardianv1beta1.ListUserAppealsRequest{} ctx := context.WithValue(context.Background(), authEmailTestContextKey{}, "test-user") res, err := s.grpcServer.ListUserAppeals(ctx, req) + fmt.Println(status.Code(err)) s.Equal(codes.Internal, status.Code(err)) s.Nil(res) s.appealService.AssertExpectations(s.T()) @@ -178,8 +189,10 @@ func (s *GrpcHandlersSuite) TestListUserAppeals() { }, }, } - s.appealService.EXPECT().Find(mock.AnythingOfType("*context.valueCtx"), mock.Anything). + s.appealService.EXPECT().Find(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). Return(invalidAppeals, nil).Once() + s.appealService.EXPECT().GetAppealsTotalCount(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). + Return(int64(1), nil).Once() req := &guardianv1beta1.ListUserAppealsRequest{} ctx := context.WithValue(context.Background(), authEmailTestContextKey{}, "test-user") @@ -288,9 +301,12 @@ func (s *GrpcHandlersSuite) TestListAppeals() { UpdatedAt: timestamppb.New(timeNow), }, }, + Total: 1, } - s.appealService.EXPECT().Find(mock.AnythingOfType("*context.emptyCtx"), expectedFilters). + s.appealService.EXPECT().Find(mock.AnythingOfType("*context.cancelCtx"), expectedFilters). Return(expectedAppeals, nil).Once() + s.appealService.EXPECT().GetAppealsTotalCount(mock.AnythingOfType("*context.cancelCtx"), expectedFilters). + Return(int64(1), nil).Once() req := &guardianv1beta1.ListAppealsRequest{ AccountId: expectedUser, @@ -313,8 +329,10 @@ func (s *GrpcHandlersSuite) TestListAppeals() { s.setup() expectedError := errors.New("random error") - s.appealService.EXPECT().Find(mock.AnythingOfType("*context.emptyCtx"), mock.Anything). + s.appealService.EXPECT().Find(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). Return(nil, expectedError).Once() + s.appealService.EXPECT().GetAppealsTotalCount(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). + Return(int64(0), nil).Once() req := &guardianv1beta1.ListAppealsRequest{} res, err := s.grpcServer.ListAppeals(context.Background(), req) @@ -334,8 +352,10 @@ func (s *GrpcHandlersSuite) TestListAppeals() { }, }, } - s.appealService.EXPECT().Find(mock.AnythingOfType("*context.emptyCtx"), mock.Anything). + s.appealService.EXPECT().Find(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). Return(invalidAppeals, nil).Once() + s.appealService.EXPECT().GetAppealsTotalCount(mock.AnythingOfType("*context.cancelCtx"), mock.Anything). + Return(int64(1), nil).Once() req := &guardianv1beta1.ListAppealsRequest{} res, err := s.grpcServer.ListAppeals(context.Background(), req) diff --git a/api/handler/v1beta1/grant.go b/api/handler/v1beta1/grant.go index 732e5f383..b66471005 100644 --- a/api/handler/v1beta1/grant.go +++ b/api/handler/v1beta1/grant.go @@ -8,12 +8,14 @@ import ( "github.com/goto/guardian/core/grant" "github.com/goto/guardian/core/provider" "github.com/goto/guardian/domain" + "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func (s *GRPCServer) ListGrants(ctx context.Context, req *guardianv1beta1.ListGrantsRequest) (*guardianv1beta1.ListGrantsResponse, error) { filter := domain.ListGrantsFilter{ + Q: req.GetQ(), Statuses: req.GetStatuses(), AccountIDs: req.GetAccountIds(), AccountTypes: req.GetAccountTypes(), @@ -29,13 +31,14 @@ func (s *GRPCServer) ListGrants(ctx context.Context, req *guardianv1beta1.ListGr Size: int(req.GetSize()), Offset: int(req.GetOffset()), } - grants, err := s.listGrants(ctx, filter) + grants, total, err := s.listGrants(ctx, filter) if err != nil { return nil, err } return &guardianv1beta1.ListGrantsResponse{ Grants: grants, + Total: int32(total), }, nil } @@ -60,13 +63,14 @@ func (s *GRPCServer) ListUserGrants(ctx context.Context, req *guardianv1beta1.Li Offset: int(req.GetOffset()), Owner: user, } - grants, err := s.listGrants(ctx, filter) + grants, total, err := s.listGrants(ctx, filter) if err != nil { return nil, err } return &guardianv1beta1.ListUserGrantsResponse{ Grants: grants, + Total: int32(total), }, nil } @@ -171,22 +175,42 @@ func (s *GRPCServer) RevokeGrants(ctx context.Context, req *guardianv1beta1.Revo }, nil } -func (s *GRPCServer) listGrants(ctx context.Context, filter domain.ListGrantsFilter) ([]*guardianv1beta1.Grant, error) { - grants, err := s.grantService.List(ctx, filter) - if err != nil { - return nil, status.Errorf(codes.Internal, "failed to list grants: %v", err) +func (s *GRPCServer) listGrants(ctx context.Context, filter domain.ListGrantsFilter) ([]*guardianv1beta1.Grant, int64, error) { + eg, ctx := errgroup.WithContext(ctx) + var grants []domain.Grant + var total int64 + + eg.Go(func() error { + grantRecords, err := s.grantService.List(ctx, filter) + if err != nil { + return status.Errorf(codes.Internal, "failed to get grant list: %s", err) + } + grants = grantRecords + return nil + }) + eg.Go(func() error { + totalRecord, err := s.grantService.GetGrantsTotalCount(ctx, filter) + if err != nil { + return status.Errorf(codes.Internal, "failed to get grant total count: %s", err) + } + total = totalRecord + return nil + }) + + if err := eg.Wait(); err != nil { + return nil, 0, err } var grantProtos []*guardianv1beta1.Grant for i, a := range grants { grantProto, err := s.adapter.ToGrantProto(&grants[i]) if err != nil { - return nil, status.Errorf(codes.Internal, "failed to parse grant %q: %v", a.ID, err) + return nil, 0, status.Errorf(codes.Internal, "failed to parse grant %q: %v", a.ID, err) } grantProtos = append(grantProtos, grantProto) } - return grantProtos, nil + return grantProtos, total, nil } func (s *GRPCServer) ImportGrantsFromProvider(ctx context.Context, req *guardianv1beta1.ImportGrantsFromProviderRequest) (*guardianv1beta1.ImportGrantsFromProviderResponse, error) { diff --git a/api/handler/v1beta1/grant_test.go b/api/handler/v1beta1/grant_test.go index 566c89b3f..c99fed055 100644 --- a/api/handler/v1beta1/grant_test.go +++ b/api/handler/v1beta1/grant_test.go @@ -66,6 +66,7 @@ func (s *GrpcHandlersSuite) TestListGrants() { }, }, }, + Total: 1, } expectedFilter := domain.ListGrantsFilter{ Statuses: []string{"test-status"}, @@ -74,8 +75,11 @@ func (s *GrpcHandlersSuite) TestListGrants() { ResourceIDs: []string{"test-resource-id"}, } s.grantService.EXPECT(). - List(mock.AnythingOfType("*context.emptyCtx"), expectedFilter). + List(mock.AnythingOfType("*context.cancelCtx"), expectedFilter). Return(dummyGrants, nil).Once() + s.grantService.EXPECT(). + GetGrantsTotalCount(mock.AnythingOfType("*context.cancelCtx"), expectedFilter). + Return(int64(1), nil).Once() req := &guardianv1beta1.ListGrantsRequest{ Statuses: expectedFilter.Statuses, @@ -95,8 +99,11 @@ func (s *GrpcHandlersSuite) TestListGrants() { expectedError := errors.New("unexpected error") s.grantService.EXPECT(). - List(mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("domain.ListGrantsFilter")). + List(mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("domain.ListGrantsFilter")). Return(nil, expectedError).Once() + s.grantService.EXPECT(). + GetGrantsTotalCount(mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("domain.ListGrantsFilter")). + Return(int64(0), nil).Once() req := &guardianv1beta1.ListGrantsRequest{} res, err := s.grpcServer.ListGrants(context.Background(), req) @@ -119,9 +126,11 @@ func (s *GrpcHandlersSuite) TestListGrants() { }, } s.grantService.EXPECT(). - List(mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("domain.ListGrantsFilter")). + List(mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("domain.ListGrantsFilter")). Return(expectedGrants, nil).Once() - + s.grantService.EXPECT(). + GetGrantsTotalCount(mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("domain.ListGrantsFilter")). + Return(int64(1), nil).Once() req := &guardianv1beta1.ListGrantsRequest{} res, err := s.grpcServer.ListGrants(context.Background(), req) diff --git a/api/handler/v1beta1/grpc.go b/api/handler/v1beta1/grpc.go index 3f603ea23..4d5bbd333 100644 --- a/api/handler/v1beta1/grpc.go +++ b/api/handler/v1beta1/grpc.go @@ -83,6 +83,7 @@ type policyService interface { //go:generate mockery --name=appealService --exported --with-expecter type appealService interface { + GetAppealsTotalCount(context.Context, *domain.ListAppealsFilter) (int64, error) GetByID(context.Context, string) (*domain.Appeal, error) Find(context.Context, *domain.ListAppealsFilter) ([]*domain.Appeal, error) Create(context.Context, []*domain.Appeal, ...appeal.CreateAppealOption) error @@ -101,6 +102,7 @@ type approvalService interface { //go:generate mockery --name=grantService --exported --with-expecter type grantService interface { + GetGrantsTotalCount(context.Context, domain.ListGrantsFilter) (int64, error) List(context.Context, domain.ListGrantsFilter) ([]domain.Grant, error) GetByID(context.Context, string) (*domain.Grant, error) Update(context.Context, *domain.Grant) error diff --git a/api/handler/v1beta1/mocks/activityService.go b/api/handler/v1beta1/mocks/activityService.go index df5b6e7d4..5062f584e 100644 --- a/api/handler/v1beta1/mocks/activityService.go +++ b/api/handler/v1beta1/mocks/activityService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *ActivityService) Find(_a0 context.Context, _a1 domain.ListProviderActi ret := _m.Called(_a0, _a1) var r0 []*domain.Activity + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListProviderActivitiesFilter) ([]*domain.Activity, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListProviderActivitiesFilter) []*domain.Activity); ok { r0 = rf(_a0, _a1) } else { @@ -35,7 +39,6 @@ func (_m *ActivityService) Find(_a0 context.Context, _a1 domain.ListProviderActi } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListProviderActivitiesFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -51,8 +54,8 @@ type ActivityService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ListProviderActivitiesFilter +// - _a0 context.Context +// - _a1 domain.ListProviderActivitiesFilter func (_e *ActivityService_Expecter) Find(_a0 interface{}, _a1 interface{}) *ActivityService_Find_Call { return &ActivityService_Find_Call{Call: _e.mock.On("Find", _a0, _a1)} } @@ -69,11 +72,20 @@ func (_c *ActivityService_Find_Call) Return(_a0 []*domain.Activity, _a1 error) * return _c } +func (_c *ActivityService_Find_Call) RunAndReturn(run func(context.Context, domain.ListProviderActivitiesFilter) ([]*domain.Activity, error)) *ActivityService_Find_Call { + _c.Call.Return(run) + return _c +} + // GetOne provides a mock function with given fields: _a0, _a1 func (_m *ActivityService) GetOne(_a0 context.Context, _a1 string) (*domain.Activity, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Activity + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Activity, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Activity); ok { r0 = rf(_a0, _a1) } else { @@ -82,7 +94,6 @@ func (_m *ActivityService) GetOne(_a0 context.Context, _a1 string) (*domain.Acti } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(_a0, _a1) } else { @@ -98,8 +109,8 @@ type ActivityService_GetOne_Call struct { } // GetOne is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *ActivityService_Expecter) GetOne(_a0 interface{}, _a1 interface{}) *ActivityService_GetOne_Call { return &ActivityService_GetOne_Call{Call: _e.mock.On("GetOne", _a0, _a1)} } @@ -116,11 +127,20 @@ func (_c *ActivityService_GetOne_Call) Return(_a0 *domain.Activity, _a1 error) * return _c } +func (_c *ActivityService_GetOne_Call) RunAndReturn(run func(context.Context, string) (*domain.Activity, error)) *ActivityService_GetOne_Call { + _c.Call.Return(run) + return _c +} + // Import provides a mock function with given fields: _a0, _a1 func (_m *ActivityService) Import(_a0 context.Context, _a1 domain.ListActivitiesFilter) ([]*domain.Activity, error) { ret := _m.Called(_a0, _a1) var r0 []*domain.Activity + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListActivitiesFilter) ([]*domain.Activity, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListActivitiesFilter) []*domain.Activity); ok { r0 = rf(_a0, _a1) } else { @@ -129,7 +149,6 @@ func (_m *ActivityService) Import(_a0 context.Context, _a1 domain.ListActivities } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListActivitiesFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -145,8 +164,8 @@ type ActivityService_Import_Call struct { } // Import is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ImportActivitiesFilter +// - _a0 context.Context +// - _a1 domain.ListActivitiesFilter func (_e *ActivityService_Expecter) Import(_a0 interface{}, _a1 interface{}) *ActivityService_Import_Call { return &ActivityService_Import_Call{Call: _e.mock.On("Import", _a0, _a1)} } @@ -162,3 +181,22 @@ func (_c *ActivityService_Import_Call) Return(_a0 []*domain.Activity, _a1 error) _c.Call.Return(_a0, _a1) return _c } + +func (_c *ActivityService_Import_Call) RunAndReturn(run func(context.Context, domain.ListActivitiesFilter) ([]*domain.Activity, error)) *ActivityService_Import_Call { + _c.Call.Return(run) + return _c +} + +// NewActivityService creates a new instance of ActivityService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewActivityService(t interface { + mock.TestingT + Cleanup(func()) +}) *ActivityService { + mock := &ActivityService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/api/handler/v1beta1/mocks/appealService.go b/api/handler/v1beta1/mocks/appealService.go index 141711ed7..6ea290b81 100644 --- a/api/handler/v1beta1/mocks/appealService.go +++ b/api/handler/v1beta1/mocks/appealService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.14.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -30,6 +30,10 @@ func (_m *AppealService) AddApprover(ctx context.Context, appealID string, appro ret := _m.Called(ctx, appealID, approvalID, email) var r0 *domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*domain.Appeal, error)); ok { + return rf(ctx, appealID, approvalID, email) + } if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *domain.Appeal); ok { r0 = rf(ctx, appealID, approvalID, email) } else { @@ -38,7 +42,6 @@ func (_m *AppealService) AddApprover(ctx context.Context, appealID string, appro } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { r1 = rf(ctx, appealID, approvalID, email) } else { @@ -54,10 +57,10 @@ type AppealService_AddApprover_Call struct { } // AddApprover is a helper method to define mock.On call -// - ctx context.Context -// - appealID string -// - approvalID string -// - email string +// - ctx context.Context +// - appealID string +// - approvalID string +// - email string func (_e *AppealService_Expecter) AddApprover(ctx interface{}, appealID interface{}, approvalID interface{}, email interface{}) *AppealService_AddApprover_Call { return &AppealService_AddApprover_Call{Call: _e.mock.On("AddApprover", ctx, appealID, approvalID, email)} } @@ -74,11 +77,20 @@ func (_c *AppealService_AddApprover_Call) Return(_a0 *domain.Appeal, _a1 error) return _c } +func (_c *AppealService_AddApprover_Call) RunAndReturn(run func(context.Context, string, string, string) (*domain.Appeal, error)) *AppealService_AddApprover_Call { + _c.Call.Return(run) + return _c +} + // Cancel provides a mock function with given fields: _a0, _a1 func (_m *AppealService) Cancel(_a0 context.Context, _a1 string) (*domain.Appeal, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Appeal, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Appeal); ok { r0 = rf(_a0, _a1) } else { @@ -87,7 +99,6 @@ func (_m *AppealService) Cancel(_a0 context.Context, _a1 string) (*domain.Appeal } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(_a0, _a1) } else { @@ -103,8 +114,8 @@ type AppealService_Cancel_Call struct { } // Cancel is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *AppealService_Expecter) Cancel(_a0 interface{}, _a1 interface{}) *AppealService_Cancel_Call { return &AppealService_Cancel_Call{Call: _e.mock.On("Cancel", _a0, _a1)} } @@ -121,6 +132,11 @@ func (_c *AppealService_Cancel_Call) Return(_a0 *domain.Appeal, _a1 error) *Appe return _c } +func (_c *AppealService_Cancel_Call) RunAndReturn(run func(context.Context, string) (*domain.Appeal, error)) *AppealService_Cancel_Call { + _c.Call.Return(run) + return _c +} + // Create provides a mock function with given fields: _a0, _a1, _a2 func (_m *AppealService) Create(_a0 context.Context, _a1 []*domain.Appeal, _a2 ...appeal.CreateAppealOption) error { _va := make([]interface{}, len(_a2)) @@ -148,9 +164,9 @@ type AppealService_Create_Call struct { } // Create is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 []*domain.Appeal -// - _a2 ...appeal.CreateAppealOption +// - _a0 context.Context +// - _a1 []*domain.Appeal +// - _a2 ...appeal.CreateAppealOption func (_e *AppealService_Expecter) Create(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AppealService_Create_Call { return &AppealService_Create_Call{Call: _e.mock.On("Create", append([]interface{}{_a0, _a1}, _a2...)...)} @@ -174,11 +190,20 @@ func (_c *AppealService_Create_Call) Return(_a0 error) *AppealService_Create_Cal return _c } +func (_c *AppealService_Create_Call) RunAndReturn(run func(context.Context, []*domain.Appeal, ...appeal.CreateAppealOption) error) *AppealService_Create_Call { + _c.Call.Return(run) + return _c +} + // DeleteApprover provides a mock function with given fields: ctx, appealID, approvalID, email func (_m *AppealService) DeleteApprover(ctx context.Context, appealID string, approvalID string, email string) (*domain.Appeal, error) { ret := _m.Called(ctx, appealID, approvalID, email) var r0 *domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*domain.Appeal, error)); ok { + return rf(ctx, appealID, approvalID, email) + } if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *domain.Appeal); ok { r0 = rf(ctx, appealID, approvalID, email) } else { @@ -187,7 +212,6 @@ func (_m *AppealService) DeleteApprover(ctx context.Context, appealID string, ap } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { r1 = rf(ctx, appealID, approvalID, email) } else { @@ -203,10 +227,10 @@ type AppealService_DeleteApprover_Call struct { } // DeleteApprover is a helper method to define mock.On call -// - ctx context.Context -// - appealID string -// - approvalID string -// - email string +// - ctx context.Context +// - appealID string +// - approvalID string +// - email string func (_e *AppealService_Expecter) DeleteApprover(ctx interface{}, appealID interface{}, approvalID interface{}, email interface{}) *AppealService_DeleteApprover_Call { return &AppealService_DeleteApprover_Call{Call: _e.mock.On("DeleteApprover", ctx, appealID, approvalID, email)} } @@ -223,11 +247,20 @@ func (_c *AppealService_DeleteApprover_Call) Return(_a0 *domain.Appeal, _a1 erro return _c } +func (_c *AppealService_DeleteApprover_Call) RunAndReturn(run func(context.Context, string, string, string) (*domain.Appeal, error)) *AppealService_DeleteApprover_Call { + _c.Call.Return(run) + return _c +} + // Find provides a mock function with given fields: _a0, _a1 func (_m *AppealService) Find(_a0 context.Context, _a1 *domain.ListAppealsFilter) ([]*domain.Appeal, error) { ret := _m.Called(_a0, _a1) var r0 []*domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) ([]*domain.Appeal, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) []*domain.Appeal); ok { r0 = rf(_a0, _a1) } else { @@ -236,7 +269,6 @@ func (_m *AppealService) Find(_a0 context.Context, _a1 *domain.ListAppealsFilter } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *domain.ListAppealsFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -252,8 +284,8 @@ type AppealService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.ListAppealsFilter +// - _a0 context.Context +// - _a1 *domain.ListAppealsFilter func (_e *AppealService_Expecter) Find(_a0 interface{}, _a1 interface{}) *AppealService_Find_Call { return &AppealService_Find_Call{Call: _e.mock.On("Find", _a0, _a1)} } @@ -270,11 +302,73 @@ func (_c *AppealService_Find_Call) Return(_a0 []*domain.Appeal, _a1 error) *Appe return _c } +func (_c *AppealService_Find_Call) RunAndReturn(run func(context.Context, *domain.ListAppealsFilter) ([]*domain.Appeal, error)) *AppealService_Find_Call { + _c.Call.Return(run) + return _c +} + +// GetAppealsTotalCount provides a mock function with given fields: _a0, _a1 +func (_m *AppealService) GetAppealsTotalCount(_a0 context.Context, _a1 *domain.ListAppealsFilter) (int64, error) { + ret := _m.Called(_a0, _a1) + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *domain.ListAppealsFilter) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AppealService_GetAppealsTotalCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAppealsTotalCount' +type AppealService_GetAppealsTotalCount_Call struct { + *mock.Call +} + +// GetAppealsTotalCount is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *domain.ListAppealsFilter +func (_e *AppealService_Expecter) GetAppealsTotalCount(_a0 interface{}, _a1 interface{}) *AppealService_GetAppealsTotalCount_Call { + return &AppealService_GetAppealsTotalCount_Call{Call: _e.mock.On("GetAppealsTotalCount", _a0, _a1)} +} + +func (_c *AppealService_GetAppealsTotalCount_Call) Run(run func(_a0 context.Context, _a1 *domain.ListAppealsFilter)) *AppealService_GetAppealsTotalCount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*domain.ListAppealsFilter)) + }) + return _c +} + +func (_c *AppealService_GetAppealsTotalCount_Call) Return(_a0 int64, _a1 error) *AppealService_GetAppealsTotalCount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AppealService_GetAppealsTotalCount_Call) RunAndReturn(run func(context.Context, *domain.ListAppealsFilter) (int64, error)) *AppealService_GetAppealsTotalCount_Call { + _c.Call.Return(run) + return _c +} + // GetByID provides a mock function with given fields: _a0, _a1 func (_m *AppealService) GetByID(_a0 context.Context, _a1 string) (*domain.Appeal, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Appeal, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Appeal); ok { r0 = rf(_a0, _a1) } else { @@ -283,7 +377,6 @@ func (_m *AppealService) GetByID(_a0 context.Context, _a1 string) (*domain.Appea } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(_a0, _a1) } else { @@ -299,8 +392,8 @@ type AppealService_GetByID_Call struct { } // GetByID is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *AppealService_Expecter) GetByID(_a0 interface{}, _a1 interface{}) *AppealService_GetByID_Call { return &AppealService_GetByID_Call{Call: _e.mock.On("GetByID", _a0, _a1)} } @@ -317,11 +410,20 @@ func (_c *AppealService_GetByID_Call) Return(_a0 *domain.Appeal, _a1 error) *App return _c } +func (_c *AppealService_GetByID_Call) RunAndReturn(run func(context.Context, string) (*domain.Appeal, error)) *AppealService_GetByID_Call { + _c.Call.Return(run) + return _c +} + // UpdateApproval provides a mock function with given fields: ctx, approvalAction func (_m *AppealService) UpdateApproval(ctx context.Context, approvalAction domain.ApprovalAction) (*domain.Appeal, error) { ret := _m.Called(ctx, approvalAction) var r0 *domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ApprovalAction) (*domain.Appeal, error)); ok { + return rf(ctx, approvalAction) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ApprovalAction) *domain.Appeal); ok { r0 = rf(ctx, approvalAction) } else { @@ -330,7 +432,6 @@ func (_m *AppealService) UpdateApproval(ctx context.Context, approvalAction doma } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ApprovalAction) error); ok { r1 = rf(ctx, approvalAction) } else { @@ -346,8 +447,8 @@ type AppealService_UpdateApproval_Call struct { } // UpdateApproval is a helper method to define mock.On call -// - ctx context.Context -// - approvalAction domain.ApprovalAction +// - ctx context.Context +// - approvalAction domain.ApprovalAction func (_e *AppealService_Expecter) UpdateApproval(ctx interface{}, approvalAction interface{}) *AppealService_UpdateApproval_Call { return &AppealService_UpdateApproval_Call{Call: _e.mock.On("UpdateApproval", ctx, approvalAction)} } @@ -364,13 +465,17 @@ func (_c *AppealService_UpdateApproval_Call) Return(_a0 *domain.Appeal, _a1 erro return _c } -type mockConstructorTestingTNewAppealService interface { - mock.TestingT - Cleanup(func()) +func (_c *AppealService_UpdateApproval_Call) RunAndReturn(run func(context.Context, domain.ApprovalAction) (*domain.Appeal, error)) *AppealService_UpdateApproval_Call { + _c.Call.Return(run) + return _c } // NewAppealService creates a new instance of AppealService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewAppealService(t mockConstructorTestingTNewAppealService) *AppealService { +// The first argument is typically a *testing.T value. +func NewAppealService(t interface { + mock.TestingT + Cleanup(func()) +}) *AppealService { mock := &AppealService{} mock.Mock.Test(t) diff --git a/api/handler/v1beta1/mocks/approvalService.go b/api/handler/v1beta1/mocks/approvalService.go index 71ad87757..f3ea26d11 100644 --- a/api/handler/v1beta1/mocks/approvalService.go +++ b/api/handler/v1beta1/mocks/approvalService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -173,13 +173,12 @@ func (_c *ApprovalService_ListApprovals_Call) RunAndReturn(run func(context.Cont return _c } -type mockConstructorTestingTNewApprovalService interface { +// NewApprovalService creates a new instance of ApprovalService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewApprovalService(t interface { mock.TestingT Cleanup(func()) -} - -// NewApprovalService creates a new instance of ApprovalService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewApprovalService(t mockConstructorTestingTNewApprovalService) *ApprovalService { +}) *ApprovalService { mock := &ApprovalService{} mock.Mock.Test(t) diff --git a/api/handler/v1beta1/mocks/grantService.go b/api/handler/v1beta1/mocks/grantService.go index d67b0fb5a..01bc38cb1 100644 --- a/api/handler/v1beta1/mocks/grantService.go +++ b/api/handler/v1beta1/mocks/grantService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -136,6 +136,59 @@ func (_c *GrantService_GetByID_Call) RunAndReturn(run func(context.Context, stri return _c } +// GetGrantsTotalCount provides a mock function with given fields: _a0, _a1 +func (_m *GrantService) GetGrantsTotalCount(_a0 context.Context, _a1 domain.ListGrantsFilter) (int64, error) { + ret := _m.Called(_a0, _a1) + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, domain.ListGrantsFilter) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrantService_GetGrantsTotalCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGrantsTotalCount' +type GrantService_GetGrantsTotalCount_Call struct { + *mock.Call +} + +// GetGrantsTotalCount is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 domain.ListGrantsFilter +func (_e *GrantService_Expecter) GetGrantsTotalCount(_a0 interface{}, _a1 interface{}) *GrantService_GetGrantsTotalCount_Call { + return &GrantService_GetGrantsTotalCount_Call{Call: _e.mock.On("GetGrantsTotalCount", _a0, _a1)} +} + +func (_c *GrantService_GetGrantsTotalCount_Call) Run(run func(_a0 context.Context, _a1 domain.ListGrantsFilter)) *GrantService_GetGrantsTotalCount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(domain.ListGrantsFilter)) + }) + return _c +} + +func (_c *GrantService_GetGrantsTotalCount_Call) Return(_a0 int64, _a1 error) *GrantService_GetGrantsTotalCount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrantService_GetGrantsTotalCount_Call) RunAndReturn(run func(context.Context, domain.ListGrantsFilter) (int64, error)) *GrantService_GetGrantsTotalCount_Call { + _c.Call.Return(run) + return _c +} + // ImportFromProvider provides a mock function with given fields: ctx, criteria func (_m *GrantService) ImportFromProvider(ctx context.Context, criteria grant.ImportFromProviderCriteria) ([]*domain.Grant, error) { ret := _m.Called(ctx, criteria) @@ -361,13 +414,12 @@ func (_c *GrantService_Update_Call) RunAndReturn(run func(context.Context, *doma return _c } -type mockConstructorTestingTNewGrantService interface { +// NewGrantService creates a new instance of GrantService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewGrantService(t interface { mock.TestingT Cleanup(func()) -} - -// NewGrantService creates a new instance of GrantService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewGrantService(t mockConstructorTestingTNewGrantService) *GrantService { +}) *GrantService { mock := &GrantService{} mock.Mock.Test(t) diff --git a/api/handler/v1beta1/mocks/policyService.go b/api/handler/v1beta1/mocks/policyService.go index cb3fe9cc4..cce84ed49 100644 --- a/api/handler/v1beta1/mocks/policyService.go +++ b/api/handler/v1beta1/mocks/policyService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -42,8 +42,8 @@ type PolicyService_Create_Call struct { } // Create is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Policy +// - _a0 context.Context +// - _a1 *domain.Policy func (_e *PolicyService_Expecter) Create(_a0 interface{}, _a1 interface{}) *PolicyService_Create_Call { return &PolicyService_Create_Call{Call: _e.mock.On("Create", _a0, _a1)} } @@ -60,11 +60,20 @@ func (_c *PolicyService_Create_Call) Return(_a0 error) *PolicyService_Create_Cal return _c } +func (_c *PolicyService_Create_Call) RunAndReturn(run func(context.Context, *domain.Policy) error) *PolicyService_Create_Call { + _c.Call.Return(run) + return _c +} + // Find provides a mock function with given fields: _a0 func (_m *PolicyService) Find(_a0 context.Context) ([]*domain.Policy, error) { ret := _m.Called(_a0) var r0 []*domain.Policy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*domain.Policy, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(context.Context) []*domain.Policy); ok { r0 = rf(_a0) } else { @@ -73,7 +82,6 @@ func (_m *PolicyService) Find(_a0 context.Context) ([]*domain.Policy, error) { } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(_a0) } else { @@ -89,7 +97,7 @@ type PolicyService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context +// - _a0 context.Context func (_e *PolicyService_Expecter) Find(_a0 interface{}) *PolicyService_Find_Call { return &PolicyService_Find_Call{Call: _e.mock.On("Find", _a0)} } @@ -106,11 +114,20 @@ func (_c *PolicyService_Find_Call) Return(_a0 []*domain.Policy, _a1 error) *Poli return _c } +func (_c *PolicyService_Find_Call) RunAndReturn(run func(context.Context) ([]*domain.Policy, error)) *PolicyService_Find_Call { + _c.Call.Return(run) + return _c +} + // GetOne provides a mock function with given fields: ctx, id, version func (_m *PolicyService) GetOne(ctx context.Context, id string, version uint) (*domain.Policy, error) { ret := _m.Called(ctx, id, version) var r0 *domain.Policy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, uint) (*domain.Policy, error)); ok { + return rf(ctx, id, version) + } if rf, ok := ret.Get(0).(func(context.Context, string, uint) *domain.Policy); ok { r0 = rf(ctx, id, version) } else { @@ -119,7 +136,6 @@ func (_m *PolicyService) GetOne(ctx context.Context, id string, version uint) (* } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, uint) error); ok { r1 = rf(ctx, id, version) } else { @@ -135,9 +151,9 @@ type PolicyService_GetOne_Call struct { } // GetOne is a helper method to define mock.On call -// - ctx context.Context -// - id string -// - version uint +// - ctx context.Context +// - id string +// - version uint func (_e *PolicyService_Expecter) GetOne(ctx interface{}, id interface{}, version interface{}) *PolicyService_GetOne_Call { return &PolicyService_GetOne_Call{Call: _e.mock.On("GetOne", ctx, id, version)} } @@ -154,6 +170,11 @@ func (_c *PolicyService_GetOne_Call) Return(_a0 *domain.Policy, _a1 error) *Poli return _c } +func (_c *PolicyService_GetOne_Call) RunAndReturn(run func(context.Context, string, uint) (*domain.Policy, error)) *PolicyService_GetOne_Call { + _c.Call.Return(run) + return _c +} + // Update provides a mock function with given fields: _a0, _a1 func (_m *PolicyService) Update(_a0 context.Context, _a1 *domain.Policy) error { ret := _m.Called(_a0, _a1) @@ -174,8 +195,8 @@ type PolicyService_Update_Call struct { } // Update is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Policy +// - _a0 context.Context +// - _a1 *domain.Policy func (_e *PolicyService_Expecter) Update(_a0 interface{}, _a1 interface{}) *PolicyService_Update_Call { return &PolicyService_Update_Call{Call: _e.mock.On("Update", _a0, _a1)} } @@ -191,3 +212,22 @@ func (_c *PolicyService_Update_Call) Return(_a0 error) *PolicyService_Update_Cal _c.Call.Return(_a0) return _c } + +func (_c *PolicyService_Update_Call) RunAndReturn(run func(context.Context, *domain.Policy) error) *PolicyService_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewPolicyService creates a new instance of PolicyService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewPolicyService(t interface { + mock.TestingT + Cleanup(func()) +}) *PolicyService { + mock := &PolicyService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/api/handler/v1beta1/mocks/providerService.go b/api/handler/v1beta1/mocks/providerService.go index 07b1dec5f..b41f29278 100644 --- a/api/handler/v1beta1/mocks/providerService.go +++ b/api/handler/v1beta1/mocks/providerService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -42,8 +42,8 @@ type ProviderService_Create_Call struct { } // Create is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Provider +// - _a0 context.Context +// - _a1 *domain.Provider func (_e *ProviderService_Expecter) Create(_a0 interface{}, _a1 interface{}) *ProviderService_Create_Call { return &ProviderService_Create_Call{Call: _e.mock.On("Create", _a0, _a1)} } @@ -60,6 +60,11 @@ func (_c *ProviderService_Create_Call) Return(_a0 error) *ProviderService_Create return _c } +func (_c *ProviderService_Create_Call) RunAndReturn(run func(context.Context, *domain.Provider) error) *ProviderService_Create_Call { + _c.Call.Return(run) + return _c +} + // Delete provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) Delete(_a0 context.Context, _a1 string) error { ret := _m.Called(_a0, _a1) @@ -80,8 +85,8 @@ type ProviderService_Delete_Call struct { } // Delete is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *ProviderService_Expecter) Delete(_a0 interface{}, _a1 interface{}) *ProviderService_Delete_Call { return &ProviderService_Delete_Call{Call: _e.mock.On("Delete", _a0, _a1)} } @@ -98,6 +103,11 @@ func (_c *ProviderService_Delete_Call) Return(_a0 error) *ProviderService_Delete return _c } +func (_c *ProviderService_Delete_Call) RunAndReturn(run func(context.Context, string) error) *ProviderService_Delete_Call { + _c.Call.Return(run) + return _c +} + // FetchResources provides a mock function with given fields: _a0 func (_m *ProviderService) FetchResources(_a0 context.Context) error { ret := _m.Called(_a0) @@ -118,7 +128,7 @@ type ProviderService_FetchResources_Call struct { } // FetchResources is a helper method to define mock.On call -// - _a0 context.Context +// - _a0 context.Context func (_e *ProviderService_Expecter) FetchResources(_a0 interface{}) *ProviderService_FetchResources_Call { return &ProviderService_FetchResources_Call{Call: _e.mock.On("FetchResources", _a0)} } @@ -135,11 +145,20 @@ func (_c *ProviderService_FetchResources_Call) Return(_a0 error) *ProviderServic return _c } +func (_c *ProviderService_FetchResources_Call) RunAndReturn(run func(context.Context) error) *ProviderService_FetchResources_Call { + _c.Call.Return(run) + return _c +} + // Find provides a mock function with given fields: _a0 func (_m *ProviderService) Find(_a0 context.Context) ([]*domain.Provider, error) { ret := _m.Called(_a0) var r0 []*domain.Provider + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*domain.Provider, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(context.Context) []*domain.Provider); ok { r0 = rf(_a0) } else { @@ -148,7 +167,6 @@ func (_m *ProviderService) Find(_a0 context.Context) ([]*domain.Provider, error) } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(_a0) } else { @@ -164,7 +182,7 @@ type ProviderService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context +// - _a0 context.Context func (_e *ProviderService_Expecter) Find(_a0 interface{}) *ProviderService_Find_Call { return &ProviderService_Find_Call{Call: _e.mock.On("Find", _a0)} } @@ -181,11 +199,20 @@ func (_c *ProviderService_Find_Call) Return(_a0 []*domain.Provider, _a1 error) * return _c } +func (_c *ProviderService_Find_Call) RunAndReturn(run func(context.Context) ([]*domain.Provider, error)) *ProviderService_Find_Call { + _c.Call.Return(run) + return _c +} + // GetByID provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) GetByID(_a0 context.Context, _a1 string) (*domain.Provider, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Provider + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Provider, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Provider); ok { r0 = rf(_a0, _a1) } else { @@ -194,7 +221,6 @@ func (_m *ProviderService) GetByID(_a0 context.Context, _a1 string) (*domain.Pro } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(_a0, _a1) } else { @@ -210,8 +236,8 @@ type ProviderService_GetByID_Call struct { } // GetByID is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *ProviderService_Expecter) GetByID(_a0 interface{}, _a1 interface{}) *ProviderService_GetByID_Call { return &ProviderService_GetByID_Call{Call: _e.mock.On("GetByID", _a0, _a1)} } @@ -228,11 +254,20 @@ func (_c *ProviderService_GetByID_Call) Return(_a0 *domain.Provider, _a1 error) return _c } +func (_c *ProviderService_GetByID_Call) RunAndReturn(run func(context.Context, string) (*domain.Provider, error)) *ProviderService_GetByID_Call { + _c.Call.Return(run) + return _c +} + // GetOne provides a mock function with given fields: ctx, pType, urn func (_m *ProviderService) GetOne(ctx context.Context, pType string, urn string) (*domain.Provider, error) { ret := _m.Called(ctx, pType, urn) var r0 *domain.Provider + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*domain.Provider, error)); ok { + return rf(ctx, pType, urn) + } if rf, ok := ret.Get(0).(func(context.Context, string, string) *domain.Provider); ok { r0 = rf(ctx, pType, urn) } else { @@ -241,7 +276,6 @@ func (_m *ProviderService) GetOne(ctx context.Context, pType string, urn string) } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { r1 = rf(ctx, pType, urn) } else { @@ -257,9 +291,9 @@ type ProviderService_GetOne_Call struct { } // GetOne is a helper method to define mock.On call -// - ctx context.Context -// - pType string -// - urn string +// - ctx context.Context +// - pType string +// - urn string func (_e *ProviderService_Expecter) GetOne(ctx interface{}, pType interface{}, urn interface{}) *ProviderService_GetOne_Call { return &ProviderService_GetOne_Call{Call: _e.mock.On("GetOne", ctx, pType, urn)} } @@ -276,11 +310,20 @@ func (_c *ProviderService_GetOne_Call) Return(_a0 *domain.Provider, _a1 error) * return _c } +func (_c *ProviderService_GetOne_Call) RunAndReturn(run func(context.Context, string, string) (*domain.Provider, error)) *ProviderService_GetOne_Call { + _c.Call.Return(run) + return _c +} + // GetRoles provides a mock function with given fields: ctx, id, resourceType func (_m *ProviderService) GetRoles(ctx context.Context, id string, resourceType string) ([]*domain.Role, error) { ret := _m.Called(ctx, id, resourceType) var r0 []*domain.Role + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]*domain.Role, error)); ok { + return rf(ctx, id, resourceType) + } if rf, ok := ret.Get(0).(func(context.Context, string, string) []*domain.Role); ok { r0 = rf(ctx, id, resourceType) } else { @@ -289,7 +332,6 @@ func (_m *ProviderService) GetRoles(ctx context.Context, id string, resourceType } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { r1 = rf(ctx, id, resourceType) } else { @@ -305,9 +347,9 @@ type ProviderService_GetRoles_Call struct { } // GetRoles is a helper method to define mock.On call -// - ctx context.Context -// - id string -// - resourceType string +// - ctx context.Context +// - id string +// - resourceType string func (_e *ProviderService_Expecter) GetRoles(ctx interface{}, id interface{}, resourceType interface{}) *ProviderService_GetRoles_Call { return &ProviderService_GetRoles_Call{Call: _e.mock.On("GetRoles", ctx, id, resourceType)} } @@ -324,11 +366,20 @@ func (_c *ProviderService_GetRoles_Call) Return(_a0 []*domain.Role, _a1 error) * return _c } +func (_c *ProviderService_GetRoles_Call) RunAndReturn(run func(context.Context, string, string) ([]*domain.Role, error)) *ProviderService_GetRoles_Call { + _c.Call.Return(run) + return _c +} + // GetTypes provides a mock function with given fields: _a0 func (_m *ProviderService) GetTypes(_a0 context.Context) ([]domain.ProviderType, error) { ret := _m.Called(_a0) var r0 []domain.ProviderType + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]domain.ProviderType, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(context.Context) []domain.ProviderType); ok { r0 = rf(_a0) } else { @@ -337,7 +388,6 @@ func (_m *ProviderService) GetTypes(_a0 context.Context) ([]domain.ProviderType, } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(_a0) } else { @@ -353,7 +403,7 @@ type ProviderService_GetTypes_Call struct { } // GetTypes is a helper method to define mock.On call -// - _a0 context.Context +// - _a0 context.Context func (_e *ProviderService_Expecter) GetTypes(_a0 interface{}) *ProviderService_GetTypes_Call { return &ProviderService_GetTypes_Call{Call: _e.mock.On("GetTypes", _a0)} } @@ -370,6 +420,11 @@ func (_c *ProviderService_GetTypes_Call) Return(_a0 []domain.ProviderType, _a1 e return _c } +func (_c *ProviderService_GetTypes_Call) RunAndReturn(run func(context.Context) ([]domain.ProviderType, error)) *ProviderService_GetTypes_Call { + _c.Call.Return(run) + return _c +} + // GrantAccess provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) GrantAccess(_a0 context.Context, _a1 domain.Grant) error { ret := _m.Called(_a0, _a1) @@ -390,8 +445,8 @@ type ProviderService_GrantAccess_Call struct { } // GrantAccess is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.Grant +// - _a0 context.Context +// - _a1 domain.Grant func (_e *ProviderService_Expecter) GrantAccess(_a0 interface{}, _a1 interface{}) *ProviderService_GrantAccess_Call { return &ProviderService_GrantAccess_Call{Call: _e.mock.On("GrantAccess", _a0, _a1)} } @@ -408,6 +463,11 @@ func (_c *ProviderService_GrantAccess_Call) Return(_a0 error) *ProviderService_G return _c } +func (_c *ProviderService_GrantAccess_Call) RunAndReturn(run func(context.Context, domain.Grant) error) *ProviderService_GrantAccess_Call { + _c.Call.Return(run) + return _c +} + // RevokeAccess provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) RevokeAccess(_a0 context.Context, _a1 domain.Grant) error { ret := _m.Called(_a0, _a1) @@ -428,8 +488,8 @@ type ProviderService_RevokeAccess_Call struct { } // RevokeAccess is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.Grant +// - _a0 context.Context +// - _a1 domain.Grant func (_e *ProviderService_Expecter) RevokeAccess(_a0 interface{}, _a1 interface{}) *ProviderService_RevokeAccess_Call { return &ProviderService_RevokeAccess_Call{Call: _e.mock.On("RevokeAccess", _a0, _a1)} } @@ -446,6 +506,11 @@ func (_c *ProviderService_RevokeAccess_Call) Return(_a0 error) *ProviderService_ return _c } +func (_c *ProviderService_RevokeAccess_Call) RunAndReturn(run func(context.Context, domain.Grant) error) *ProviderService_RevokeAccess_Call { + _c.Call.Return(run) + return _c +} + // Update provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) Update(_a0 context.Context, _a1 *domain.Provider) error { ret := _m.Called(_a0, _a1) @@ -466,8 +531,8 @@ type ProviderService_Update_Call struct { } // Update is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Provider +// - _a0 context.Context +// - _a1 *domain.Provider func (_e *ProviderService_Expecter) Update(_a0 interface{}, _a1 interface{}) *ProviderService_Update_Call { return &ProviderService_Update_Call{Call: _e.mock.On("Update", _a0, _a1)} } @@ -484,6 +549,11 @@ func (_c *ProviderService_Update_Call) Return(_a0 error) *ProviderService_Update return _c } +func (_c *ProviderService_Update_Call) RunAndReturn(run func(context.Context, *domain.Provider) error) *ProviderService_Update_Call { + _c.Call.Return(run) + return _c +} + // ValidateAppeal provides a mock function with given fields: _a0, _a1, _a2, _a3 func (_m *ProviderService) ValidateAppeal(_a0 context.Context, _a1 *domain.Appeal, _a2 *domain.Provider, _a3 *domain.Policy) error { ret := _m.Called(_a0, _a1, _a2, _a3) @@ -504,10 +574,10 @@ type ProviderService_ValidateAppeal_Call struct { } // ValidateAppeal is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Appeal -// - _a2 *domain.Provider -// - _a3 *domain.Policy +// - _a0 context.Context +// - _a1 *domain.Appeal +// - _a2 *domain.Provider +// - _a3 *domain.Policy func (_e *ProviderService_Expecter) ValidateAppeal(_a0 interface{}, _a1 interface{}, _a2 interface{}, _a3 interface{}) *ProviderService_ValidateAppeal_Call { return &ProviderService_ValidateAppeal_Call{Call: _e.mock.On("ValidateAppeal", _a0, _a1, _a2, _a3)} } @@ -523,3 +593,22 @@ func (_c *ProviderService_ValidateAppeal_Call) Return(_a0 error) *ProviderServic _c.Call.Return(_a0) return _c } + +func (_c *ProviderService_ValidateAppeal_Call) RunAndReturn(run func(context.Context, *domain.Appeal, *domain.Provider, *domain.Policy) error) *ProviderService_ValidateAppeal_Call { + _c.Call.Return(run) + return _c +} + +// NewProviderService creates a new instance of ProviderService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProviderService(t interface { + mock.TestingT + Cleanup(func()) +}) *ProviderService { + mock := &ProviderService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/api/handler/v1beta1/mocks/resourceService.go b/api/handler/v1beta1/mocks/resourceService.go index 26882ee6b..00887f035 100644 --- a/api/handler/v1beta1/mocks/resourceService.go +++ b/api/handler/v1beta1/mocks/resourceService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -42,8 +42,8 @@ type ResourceService_BatchDelete_Call struct { } // BatchDelete is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 []string +// - _a0 context.Context +// - _a1 []string func (_e *ResourceService_Expecter) BatchDelete(_a0 interface{}, _a1 interface{}) *ResourceService_BatchDelete_Call { return &ResourceService_BatchDelete_Call{Call: _e.mock.On("BatchDelete", _a0, _a1)} } @@ -60,6 +60,11 @@ func (_c *ResourceService_BatchDelete_Call) Return(_a0 error) *ResourceService_B return _c } +func (_c *ResourceService_BatchDelete_Call) RunAndReturn(run func(context.Context, []string) error) *ResourceService_BatchDelete_Call { + _c.Call.Return(run) + return _c +} + // BulkUpsert provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) BulkUpsert(_a0 context.Context, _a1 []*domain.Resource) error { ret := _m.Called(_a0, _a1) @@ -80,8 +85,8 @@ type ResourceService_BulkUpsert_Call struct { } // BulkUpsert is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 []*domain.Resource +// - _a0 context.Context +// - _a1 []*domain.Resource func (_e *ResourceService_Expecter) BulkUpsert(_a0 interface{}, _a1 interface{}) *ResourceService_BulkUpsert_Call { return &ResourceService_BulkUpsert_Call{Call: _e.mock.On("BulkUpsert", _a0, _a1)} } @@ -98,6 +103,11 @@ func (_c *ResourceService_BulkUpsert_Call) Return(_a0 error) *ResourceService_Bu return _c } +func (_c *ResourceService_BulkUpsert_Call) RunAndReturn(run func(context.Context, []*domain.Resource) error) *ResourceService_BulkUpsert_Call { + _c.Call.Return(run) + return _c +} + // Delete provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) Delete(_a0 context.Context, _a1 string) error { ret := _m.Called(_a0, _a1) @@ -118,8 +128,8 @@ type ResourceService_Delete_Call struct { } // Delete is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *ResourceService_Expecter) Delete(_a0 interface{}, _a1 interface{}) *ResourceService_Delete_Call { return &ResourceService_Delete_Call{Call: _e.mock.On("Delete", _a0, _a1)} } @@ -136,11 +146,20 @@ func (_c *ResourceService_Delete_Call) Return(_a0 error) *ResourceService_Delete return _c } +func (_c *ResourceService_Delete_Call) RunAndReturn(run func(context.Context, string) error) *ResourceService_Delete_Call { + _c.Call.Return(run) + return _c +} + // Find provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) Find(_a0 context.Context, _a1 domain.ListResourcesFilter) ([]*domain.Resource, error) { ret := _m.Called(_a0, _a1) var r0 []*domain.Resource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListResourcesFilter) []*domain.Resource); ok { r0 = rf(_a0, _a1) } else { @@ -149,7 +168,6 @@ func (_m *ResourceService) Find(_a0 context.Context, _a1 domain.ListResourcesFil } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListResourcesFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -165,8 +183,8 @@ type ResourceService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ListResourcesFilter +// - _a0 context.Context +// - _a1 domain.ListResourcesFilter func (_e *ResourceService_Expecter) Find(_a0 interface{}, _a1 interface{}) *ResourceService_Find_Call { return &ResourceService_Find_Call{Call: _e.mock.On("Find", _a0, _a1)} } @@ -183,11 +201,20 @@ func (_c *ResourceService_Find_Call) Return(_a0 []*domain.Resource, _a1 error) * return _c } +func (_c *ResourceService_Find_Call) RunAndReturn(run func(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error)) *ResourceService_Find_Call { + _c.Call.Return(run) + return _c +} + // Get provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) Get(_a0 context.Context, _a1 *domain.ResourceIdentifier) (*domain.Resource, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Resource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ResourceIdentifier) (*domain.Resource, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *domain.ResourceIdentifier) *domain.Resource); ok { r0 = rf(_a0, _a1) } else { @@ -196,7 +223,6 @@ func (_m *ResourceService) Get(_a0 context.Context, _a1 *domain.ResourceIdentifi } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *domain.ResourceIdentifier) error); ok { r1 = rf(_a0, _a1) } else { @@ -212,8 +238,8 @@ type ResourceService_Get_Call struct { } // Get is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.ResourceIdentifier +// - _a0 context.Context +// - _a1 *domain.ResourceIdentifier func (_e *ResourceService_Expecter) Get(_a0 interface{}, _a1 interface{}) *ResourceService_Get_Call { return &ResourceService_Get_Call{Call: _e.mock.On("Get", _a0, _a1)} } @@ -230,11 +256,20 @@ func (_c *ResourceService_Get_Call) Return(_a0 *domain.Resource, _a1 error) *Res return _c } +func (_c *ResourceService_Get_Call) RunAndReturn(run func(context.Context, *domain.ResourceIdentifier) (*domain.Resource, error)) *ResourceService_Get_Call { + _c.Call.Return(run) + return _c +} + // GetOne provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) GetOne(_a0 context.Context, _a1 string) (*domain.Resource, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Resource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Resource, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Resource); ok { r0 = rf(_a0, _a1) } else { @@ -243,7 +278,6 @@ func (_m *ResourceService) GetOne(_a0 context.Context, _a1 string) (*domain.Reso } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(_a0, _a1) } else { @@ -259,8 +293,8 @@ type ResourceService_GetOne_Call struct { } // GetOne is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *ResourceService_Expecter) GetOne(_a0 interface{}, _a1 interface{}) *ResourceService_GetOne_Call { return &ResourceService_GetOne_Call{Call: _e.mock.On("GetOne", _a0, _a1)} } @@ -277,6 +311,11 @@ func (_c *ResourceService_GetOne_Call) Return(_a0 *domain.Resource, _a1 error) * return _c } +func (_c *ResourceService_GetOne_Call) RunAndReturn(run func(context.Context, string) (*domain.Resource, error)) *ResourceService_GetOne_Call { + _c.Call.Return(run) + return _c +} + // Update provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) Update(_a0 context.Context, _a1 *domain.Resource) error { ret := _m.Called(_a0, _a1) @@ -297,8 +336,8 @@ type ResourceService_Update_Call struct { } // Update is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Resource +// - _a0 context.Context +// - _a1 *domain.Resource func (_e *ResourceService_Expecter) Update(_a0 interface{}, _a1 interface{}) *ResourceService_Update_Call { return &ResourceService_Update_Call{Call: _e.mock.On("Update", _a0, _a1)} } @@ -314,3 +353,22 @@ func (_c *ResourceService_Update_Call) Return(_a0 error) *ResourceService_Update _c.Call.Return(_a0) return _c } + +func (_c *ResourceService_Update_Call) RunAndReturn(run func(context.Context, *domain.Resource) error) *ResourceService_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewResourceService creates a new instance of ResourceService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewResourceService(t interface { + mock.TestingT + Cleanup(func()) +}) *ResourceService { + mock := &ResourceService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/buf.gen.yaml b/buf.gen.yaml index 2c944aac9..40bbf24af 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -5,13 +5,13 @@ plugins: opt: paths=source_relative - plugin: buf.build/grpc/go:v1.2.0 out: api/proto - opt: paths=source_relative,require_unimplemented_servers=true + opt: paths=source_relative, require_unimplemented_servers=true - plugin: buf.build/grpc-ecosystem/gateway:v2.15.1 out: api/proto opt: paths=source_relative - plugin: buf.build/grpc-ecosystem/openapiv2:v2.15.1 out: third_party/OpenAPI - # See https://github.com/bufbuild/protoc-gen-validate/issues/523 +# See https://github.com/bufbuild/protoc-gen-validate/issues/523 - remote: buf.build/jirkad/plugins/protoc-gen-validate:v0.6.7 out: api/proto opt: diff --git a/core/appeal/mocks/approvalService.go b/core/appeal/mocks/approvalService.go index af1f50cbb..424cf781f 100644 --- a/core/appeal/mocks/approvalService.go +++ b/core/appeal/mocks/approvalService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.14.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -41,9 +41,9 @@ type ApprovalService_AddApprover_Call struct { } // AddApprover is a helper method to define mock.On call -// - ctx context.Context -// - approvalID string -// - email string +// - ctx context.Context +// - approvalID string +// - email string func (_e *ApprovalService_Expecter) AddApprover(ctx interface{}, approvalID interface{}, email interface{}) *ApprovalService_AddApprover_Call { return &ApprovalService_AddApprover_Call{Call: _e.mock.On("AddApprover", ctx, approvalID, email)} } @@ -60,6 +60,11 @@ func (_c *ApprovalService_AddApprover_Call) Return(_a0 error) *ApprovalService_A return _c } +func (_c *ApprovalService_AddApprover_Call) RunAndReturn(run func(context.Context, string, string) error) *ApprovalService_AddApprover_Call { + _c.Call.Return(run) + return _c +} + // DeleteApprover provides a mock function with given fields: ctx, approvalID, email func (_m *ApprovalService) DeleteApprover(ctx context.Context, approvalID string, email string) error { ret := _m.Called(ctx, approvalID, email) @@ -80,9 +85,9 @@ type ApprovalService_DeleteApprover_Call struct { } // DeleteApprover is a helper method to define mock.On call -// - ctx context.Context -// - approvalID string -// - email string +// - ctx context.Context +// - approvalID string +// - email string func (_e *ApprovalService_Expecter) DeleteApprover(ctx interface{}, approvalID interface{}, email interface{}) *ApprovalService_DeleteApprover_Call { return &ApprovalService_DeleteApprover_Call{Call: _e.mock.On("DeleteApprover", ctx, approvalID, email)} } @@ -99,13 +104,17 @@ func (_c *ApprovalService_DeleteApprover_Call) Return(_a0 error) *ApprovalServic return _c } -type mockConstructorTestingTNewApprovalService interface { - mock.TestingT - Cleanup(func()) +func (_c *ApprovalService_DeleteApprover_Call) RunAndReturn(run func(context.Context, string, string) error) *ApprovalService_DeleteApprover_Call { + _c.Call.Return(run) + return _c } // NewApprovalService creates a new instance of ApprovalService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewApprovalService(t mockConstructorTestingTNewApprovalService) *ApprovalService { +// The first argument is typically a *testing.T value. +func NewApprovalService(t interface { + mock.TestingT + Cleanup(func()) +}) *ApprovalService { mock := &ApprovalService{} mock.Mock.Test(t) diff --git a/core/appeal/mocks/auditLogger.go b/core/appeal/mocks/auditLogger.go index 421d831ee..d13bf9441 100644 --- a/core/appeal/mocks/auditLogger.go +++ b/core/appeal/mocks/auditLogger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -41,9 +41,9 @@ type AuditLogger_Log_Call struct { } // Log is a helper method to define mock.On call -// - ctx context.Context -// - action string -// - data interface{} +// - ctx context.Context +// - action string +// - data interface{} func (_e *AuditLogger_Expecter) Log(ctx interface{}, action interface{}, data interface{}) *AuditLogger_Log_Call { return &AuditLogger_Log_Call{Call: _e.mock.On("Log", ctx, action, data)} } @@ -59,3 +59,22 @@ func (_c *AuditLogger_Log_Call) Return(_a0 error) *AuditLogger_Log_Call { _c.Call.Return(_a0) return _c } + +func (_c *AuditLogger_Log_Call) RunAndReturn(run func(context.Context, string, interface{}) error) *AuditLogger_Log_Call { + _c.Call.Return(run) + return _c +} + +// NewAuditLogger creates a new instance of AuditLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAuditLogger(t interface { + mock.TestingT + Cleanup(func()) +}) *AuditLogger { + mock := &AuditLogger{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/grantService.go b/core/appeal/mocks/grantService.go index 8143f6c04..1de2c8039 100644 --- a/core/appeal/mocks/grantService.go +++ b/core/appeal/mocks/grantService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -29,6 +29,10 @@ func (_m *GrantService) List(_a0 context.Context, _a1 domain.ListGrantsFilter) ( ret := _m.Called(_a0, _a1) var r0 []domain.Grant + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) ([]domain.Grant, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) []domain.Grant); ok { r0 = rf(_a0, _a1) } else { @@ -37,7 +41,6 @@ func (_m *GrantService) List(_a0 context.Context, _a1 domain.ListGrantsFilter) ( } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListGrantsFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -53,8 +56,8 @@ type GrantService_List_Call struct { } // List is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ListGrantsFilter +// - _a0 context.Context +// - _a1 domain.ListGrantsFilter func (_e *GrantService_Expecter) List(_a0 interface{}, _a1 interface{}) *GrantService_List_Call { return &GrantService_List_Call{Call: _e.mock.On("List", _a0, _a1)} } @@ -71,11 +74,20 @@ func (_c *GrantService_List_Call) Return(_a0 []domain.Grant, _a1 error) *GrantSe return _c } +func (_c *GrantService_List_Call) RunAndReturn(run func(context.Context, domain.ListGrantsFilter) ([]domain.Grant, error)) *GrantService_List_Call { + _c.Call.Return(run) + return _c +} + // Prepare provides a mock function with given fields: _a0, _a1 func (_m *GrantService) Prepare(_a0 context.Context, _a1 domain.Appeal) (*domain.Grant, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Grant + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.Appeal) (*domain.Grant, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.Appeal) *domain.Grant); ok { r0 = rf(_a0, _a1) } else { @@ -84,7 +96,6 @@ func (_m *GrantService) Prepare(_a0 context.Context, _a1 domain.Appeal) (*domain } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.Appeal) error); ok { r1 = rf(_a0, _a1) } else { @@ -100,8 +111,8 @@ type GrantService_Prepare_Call struct { } // Prepare is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.Appeal +// - _a0 context.Context +// - _a1 domain.Appeal func (_e *GrantService_Expecter) Prepare(_a0 interface{}, _a1 interface{}) *GrantService_Prepare_Call { return &GrantService_Prepare_Call{Call: _e.mock.On("Prepare", _a0, _a1)} } @@ -118,6 +129,11 @@ func (_c *GrantService_Prepare_Call) Return(_a0 *domain.Grant, _a1 error) *Grant return _c } +func (_c *GrantService_Prepare_Call) RunAndReturn(run func(context.Context, domain.Appeal) (*domain.Grant, error)) *GrantService_Prepare_Call { + _c.Call.Return(run) + return _c +} + // Revoke provides a mock function with given fields: ctx, id, actor, reason, opts func (_m *GrantService) Revoke(ctx context.Context, id string, actor string, reason string, opts ...grant.Option) (*domain.Grant, error) { _va := make([]interface{}, len(opts)) @@ -130,6 +146,10 @@ func (_m *GrantService) Revoke(ctx context.Context, id string, actor string, rea ret := _m.Called(_ca...) var r0 *domain.Grant + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, ...grant.Option) (*domain.Grant, error)); ok { + return rf(ctx, id, actor, reason, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, string, string, string, ...grant.Option) *domain.Grant); ok { r0 = rf(ctx, id, actor, reason, opts...) } else { @@ -138,7 +158,6 @@ func (_m *GrantService) Revoke(ctx context.Context, id string, actor string, rea } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string, string, ...grant.Option) error); ok { r1 = rf(ctx, id, actor, reason, opts...) } else { @@ -154,11 +173,11 @@ type GrantService_Revoke_Call struct { } // Revoke is a helper method to define mock.On call -// - ctx context.Context -// - id string -// - actor string -// - reason string -// - opts ...grant.Option +// - ctx context.Context +// - id string +// - actor string +// - reason string +// - opts ...grant.Option func (_e *GrantService_Expecter) Revoke(ctx interface{}, id interface{}, actor interface{}, reason interface{}, opts ...interface{}) *GrantService_Revoke_Call { return &GrantService_Revoke_Call{Call: _e.mock.On("Revoke", append([]interface{}{ctx, id, actor, reason}, opts...)...)} @@ -181,3 +200,22 @@ func (_c *GrantService_Revoke_Call) Return(_a0 *domain.Grant, _a1 error) *GrantS _c.Call.Return(_a0, _a1) return _c } + +func (_c *GrantService_Revoke_Call) RunAndReturn(run func(context.Context, string, string, string, ...grant.Option) (*domain.Grant, error)) *GrantService_Revoke_Call { + _c.Call.Return(run) + return _c +} + +// NewGrantService creates a new instance of GrantService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewGrantService(t interface { + mock.TestingT + Cleanup(func()) +}) *GrantService { + mock := &GrantService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/iamManager.go b/core/appeal/mocks/iamManager.go index bd6a3469c..1c9c6fc41 100644 --- a/core/appeal/mocks/iamManager.go +++ b/core/appeal/mocks/iamManager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ func (_m *IamManager) GetClient(_a0 domain.SensitiveConfig) (domain.IAMClient, e ret := _m.Called(_a0) var r0 domain.IAMClient + var r1 error + if rf, ok := ret.Get(0).(func(domain.SensitiveConfig) (domain.IAMClient, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(domain.SensitiveConfig) domain.IAMClient); ok { r0 = rf(_a0) } else { @@ -33,7 +37,6 @@ func (_m *IamManager) GetClient(_a0 domain.SensitiveConfig) (domain.IAMClient, e } } - var r1 error if rf, ok := ret.Get(1).(func(domain.SensitiveConfig) error); ok { r1 = rf(_a0) } else { @@ -49,7 +52,7 @@ type IamManager_GetClient_Call struct { } // GetClient is a helper method to define mock.On call -// - _a0 domain.SensitiveConfig +// - _a0 domain.SensitiveConfig func (_e *IamManager_Expecter) GetClient(_a0 interface{}) *IamManager_GetClient_Call { return &IamManager_GetClient_Call{Call: _e.mock.On("GetClient", _a0)} } @@ -66,11 +69,20 @@ func (_c *IamManager_GetClient_Call) Return(_a0 domain.IAMClient, _a1 error) *Ia return _c } +func (_c *IamManager_GetClient_Call) RunAndReturn(run func(domain.SensitiveConfig) (domain.IAMClient, error)) *IamManager_GetClient_Call { + _c.Call.Return(run) + return _c +} + // ParseConfig provides a mock function with given fields: _a0 func (_m *IamManager) ParseConfig(_a0 *domain.IAMConfig) (domain.SensitiveConfig, error) { ret := _m.Called(_a0) var r0 domain.SensitiveConfig + var r1 error + if rf, ok := ret.Get(0).(func(*domain.IAMConfig) (domain.SensitiveConfig, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(*domain.IAMConfig) domain.SensitiveConfig); ok { r0 = rf(_a0) } else { @@ -79,7 +91,6 @@ func (_m *IamManager) ParseConfig(_a0 *domain.IAMConfig) (domain.SensitiveConfig } } - var r1 error if rf, ok := ret.Get(1).(func(*domain.IAMConfig) error); ok { r1 = rf(_a0) } else { @@ -95,7 +106,7 @@ type IamManager_ParseConfig_Call struct { } // ParseConfig is a helper method to define mock.On call -// - _a0 *domain.IAMConfig +// - _a0 *domain.IAMConfig func (_e *IamManager_Expecter) ParseConfig(_a0 interface{}) *IamManager_ParseConfig_Call { return &IamManager_ParseConfig_Call{Call: _e.mock.On("ParseConfig", _a0)} } @@ -111,3 +122,22 @@ func (_c *IamManager_ParseConfig_Call) Return(_a0 domain.SensitiveConfig, _a1 er _c.Call.Return(_a0, _a1) return _c } + +func (_c *IamManager_ParseConfig_Call) RunAndReturn(run func(*domain.IAMConfig) (domain.SensitiveConfig, error)) *IamManager_ParseConfig_Call { + _c.Call.Return(run) + return _c +} + +// NewIamManager creates a new instance of IamManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewIamManager(t interface { + mock.TestingT + Cleanup(func()) +}) *IamManager { + mock := &IamManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/notifier.go b/core/appeal/mocks/notifier.go index 33993fa1e..9d8970869 100644 --- a/core/appeal/mocks/notifier.go +++ b/core/appeal/mocks/notifier.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -42,7 +42,7 @@ type Notifier_Notify_Call struct { } // Notify is a helper method to define mock.On call -// - _a0 []domain.Notification +// - _a0 []domain.Notification func (_e *Notifier_Expecter) Notify(_a0 interface{}) *Notifier_Notify_Call { return &Notifier_Notify_Call{Call: _e.mock.On("Notify", _a0)} } @@ -58,3 +58,22 @@ func (_c *Notifier_Notify_Call) Return(_a0 []error) *Notifier_Notify_Call { _c.Call.Return(_a0) return _c } + +func (_c *Notifier_Notify_Call) RunAndReturn(run func([]domain.Notification) []error) *Notifier_Notify_Call { + _c.Call.Return(run) + return _c +} + +// NewNotifier creates a new instance of Notifier. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewNotifier(t interface { + mock.TestingT + Cleanup(func()) +}) *Notifier { + mock := &Notifier{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/policyService.go b/core/appeal/mocks/policyService.go index 6114b39e9..fc0df7f4f 100644 --- a/core/appeal/mocks/policyService.go +++ b/core/appeal/mocks/policyService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *PolicyService) Find(_a0 context.Context) ([]*domain.Policy, error) { ret := _m.Called(_a0) var r0 []*domain.Policy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*domain.Policy, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(context.Context) []*domain.Policy); ok { r0 = rf(_a0) } else { @@ -35,7 +39,6 @@ func (_m *PolicyService) Find(_a0 context.Context) ([]*domain.Policy, error) { } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(_a0) } else { @@ -51,7 +54,7 @@ type PolicyService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context +// - _a0 context.Context func (_e *PolicyService_Expecter) Find(_a0 interface{}) *PolicyService_Find_Call { return &PolicyService_Find_Call{Call: _e.mock.On("Find", _a0)} } @@ -68,11 +71,20 @@ func (_c *PolicyService_Find_Call) Return(_a0 []*domain.Policy, _a1 error) *Poli return _c } +func (_c *PolicyService_Find_Call) RunAndReturn(run func(context.Context) ([]*domain.Policy, error)) *PolicyService_Find_Call { + _c.Call.Return(run) + return _c +} + // GetOne provides a mock function with given fields: _a0, _a1, _a2 func (_m *PolicyService) GetOne(_a0 context.Context, _a1 string, _a2 uint) (*domain.Policy, error) { ret := _m.Called(_a0, _a1, _a2) var r0 *domain.Policy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, uint) (*domain.Policy, error)); ok { + return rf(_a0, _a1, _a2) + } if rf, ok := ret.Get(0).(func(context.Context, string, uint) *domain.Policy); ok { r0 = rf(_a0, _a1, _a2) } else { @@ -81,7 +93,6 @@ func (_m *PolicyService) GetOne(_a0 context.Context, _a1 string, _a2 uint) (*dom } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, uint) error); ok { r1 = rf(_a0, _a1, _a2) } else { @@ -97,9 +108,9 @@ type PolicyService_GetOne_Call struct { } // GetOne is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string -// - _a2 uint +// - _a0 context.Context +// - _a1 string +// - _a2 uint func (_e *PolicyService_Expecter) GetOne(_a0 interface{}, _a1 interface{}, _a2 interface{}) *PolicyService_GetOne_Call { return &PolicyService_GetOne_Call{Call: _e.mock.On("GetOne", _a0, _a1, _a2)} } @@ -115,3 +126,22 @@ func (_c *PolicyService_GetOne_Call) Return(_a0 *domain.Policy, _a1 error) *Poli _c.Call.Return(_a0, _a1) return _c } + +func (_c *PolicyService_GetOne_Call) RunAndReturn(run func(context.Context, string, uint) (*domain.Policy, error)) *PolicyService_GetOne_Call { + _c.Call.Return(run) + return _c +} + +// NewPolicyService creates a new instance of PolicyService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewPolicyService(t interface { + mock.TestingT + Cleanup(func()) +}) *PolicyService { + mock := &PolicyService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/providerService.go b/core/appeal/mocks/providerService.go index 36de59793..95d4d8929 100644 --- a/core/appeal/mocks/providerService.go +++ b/core/appeal/mocks/providerService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *ProviderService) Find(_a0 context.Context) ([]*domain.Provider, error) ret := _m.Called(_a0) var r0 []*domain.Provider + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*domain.Provider, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(context.Context) []*domain.Provider); ok { r0 = rf(_a0) } else { @@ -35,7 +39,6 @@ func (_m *ProviderService) Find(_a0 context.Context) ([]*domain.Provider, error) } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(_a0) } else { @@ -51,7 +54,7 @@ type ProviderService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context +// - _a0 context.Context func (_e *ProviderService_Expecter) Find(_a0 interface{}) *ProviderService_Find_Call { return &ProviderService_Find_Call{Call: _e.mock.On("Find", _a0)} } @@ -68,11 +71,20 @@ func (_c *ProviderService_Find_Call) Return(_a0 []*domain.Provider, _a1 error) * return _c } +func (_c *ProviderService_Find_Call) RunAndReturn(run func(context.Context) ([]*domain.Provider, error)) *ProviderService_Find_Call { + _c.Call.Return(run) + return _c +} + // GetPermissions provides a mock function with given fields: _a0, _a1, _a2, _a3 func (_m *ProviderService) GetPermissions(_a0 context.Context, _a1 *domain.ProviderConfig, _a2 string, _a3 string) ([]interface{}, error) { ret := _m.Called(_a0, _a1, _a2, _a3) var r0 []interface{} + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ProviderConfig, string, string) ([]interface{}, error)); ok { + return rf(_a0, _a1, _a2, _a3) + } if rf, ok := ret.Get(0).(func(context.Context, *domain.ProviderConfig, string, string) []interface{}); ok { r0 = rf(_a0, _a1, _a2, _a3) } else { @@ -81,7 +93,6 @@ func (_m *ProviderService) GetPermissions(_a0 context.Context, _a1 *domain.Provi } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *domain.ProviderConfig, string, string) error); ok { r1 = rf(_a0, _a1, _a2, _a3) } else { @@ -97,10 +108,10 @@ type ProviderService_GetPermissions_Call struct { } // GetPermissions is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.ProviderConfig -// - _a2 string -// - _a3 string +// - _a0 context.Context +// - _a1 *domain.ProviderConfig +// - _a2 string +// - _a3 string func (_e *ProviderService_Expecter) GetPermissions(_a0 interface{}, _a1 interface{}, _a2 interface{}, _a3 interface{}) *ProviderService_GetPermissions_Call { return &ProviderService_GetPermissions_Call{Call: _e.mock.On("GetPermissions", _a0, _a1, _a2, _a3)} } @@ -117,6 +128,11 @@ func (_c *ProviderService_GetPermissions_Call) Return(_a0 []interface{}, _a1 err return _c } +func (_c *ProviderService_GetPermissions_Call) RunAndReturn(run func(context.Context, *domain.ProviderConfig, string, string) ([]interface{}, error)) *ProviderService_GetPermissions_Call { + _c.Call.Return(run) + return _c +} + // GrantAccess provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) GrantAccess(_a0 context.Context, _a1 domain.Grant) error { ret := _m.Called(_a0, _a1) @@ -137,8 +153,8 @@ type ProviderService_GrantAccess_Call struct { } // GrantAccess is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.Grant +// - _a0 context.Context +// - _a1 domain.Grant func (_e *ProviderService_Expecter) GrantAccess(_a0 interface{}, _a1 interface{}) *ProviderService_GrantAccess_Call { return &ProviderService_GrantAccess_Call{Call: _e.mock.On("GrantAccess", _a0, _a1)} } @@ -155,6 +171,11 @@ func (_c *ProviderService_GrantAccess_Call) Return(_a0 error) *ProviderService_G return _c } +func (_c *ProviderService_GrantAccess_Call) RunAndReturn(run func(context.Context, domain.Grant) error) *ProviderService_GrantAccess_Call { + _c.Call.Return(run) + return _c +} + // RevokeAccess provides a mock function with given fields: _a0, _a1 func (_m *ProviderService) RevokeAccess(_a0 context.Context, _a1 domain.Grant) error { ret := _m.Called(_a0, _a1) @@ -175,8 +196,8 @@ type ProviderService_RevokeAccess_Call struct { } // RevokeAccess is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.Grant +// - _a0 context.Context +// - _a1 domain.Grant func (_e *ProviderService_Expecter) RevokeAccess(_a0 interface{}, _a1 interface{}) *ProviderService_RevokeAccess_Call { return &ProviderService_RevokeAccess_Call{Call: _e.mock.On("RevokeAccess", _a0, _a1)} } @@ -193,6 +214,11 @@ func (_c *ProviderService_RevokeAccess_Call) Return(_a0 error) *ProviderService_ return _c } +func (_c *ProviderService_RevokeAccess_Call) RunAndReturn(run func(context.Context, domain.Grant) error) *ProviderService_RevokeAccess_Call { + _c.Call.Return(run) + return _c +} + // ValidateAppeal provides a mock function with given fields: _a0, _a1, _a2, _a3 func (_m *ProviderService) ValidateAppeal(_a0 context.Context, _a1 *domain.Appeal, _a2 *domain.Provider, _a3 *domain.Policy) error { ret := _m.Called(_a0, _a1, _a2, _a3) @@ -213,10 +239,10 @@ type ProviderService_ValidateAppeal_Call struct { } // ValidateAppeal is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Appeal -// - _a2 *domain.Provider -// - _a3 *domain.Policy +// - _a0 context.Context +// - _a1 *domain.Appeal +// - _a2 *domain.Provider +// - _a3 *domain.Policy func (_e *ProviderService_Expecter) ValidateAppeal(_a0 interface{}, _a1 interface{}, _a2 interface{}, _a3 interface{}) *ProviderService_ValidateAppeal_Call { return &ProviderService_ValidateAppeal_Call{Call: _e.mock.On("ValidateAppeal", _a0, _a1, _a2, _a3)} } @@ -232,3 +258,22 @@ func (_c *ProviderService_ValidateAppeal_Call) Return(_a0 error) *ProviderServic _c.Call.Return(_a0) return _c } + +func (_c *ProviderService_ValidateAppeal_Call) RunAndReturn(run func(context.Context, *domain.Appeal, *domain.Provider, *domain.Policy) error) *ProviderService_ValidateAppeal_Call { + _c.Call.Return(run) + return _c +} + +// NewProviderService creates a new instance of ProviderService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProviderService(t interface { + mock.TestingT + Cleanup(func()) +}) *ProviderService { + mock := &ProviderService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/repository.go b/core/appeal/mocks/repository.go index 5d110720f..6726f175d 100644 --- a/core/appeal/mocks/repository.go +++ b/core/appeal/mocks/repository.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -42,8 +42,8 @@ type Repository_BulkUpsert_Call struct { } // BulkUpsert is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 []*domain.Appeal +// - _a0 context.Context +// - _a1 []*domain.Appeal func (_e *Repository_Expecter) BulkUpsert(_a0 interface{}, _a1 interface{}) *Repository_BulkUpsert_Call { return &Repository_BulkUpsert_Call{Call: _e.mock.On("BulkUpsert", _a0, _a1)} } @@ -60,11 +60,20 @@ func (_c *Repository_BulkUpsert_Call) Return(_a0 error) *Repository_BulkUpsert_C return _c } +func (_c *Repository_BulkUpsert_Call) RunAndReturn(run func(context.Context, []*domain.Appeal) error) *Repository_BulkUpsert_Call { + _c.Call.Return(run) + return _c +} + // Find provides a mock function with given fields: _a0, _a1 func (_m *Repository) Find(_a0 context.Context, _a1 *domain.ListAppealsFilter) ([]*domain.Appeal, error) { ret := _m.Called(_a0, _a1) var r0 []*domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) ([]*domain.Appeal, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) []*domain.Appeal); ok { r0 = rf(_a0, _a1) } else { @@ -73,7 +82,6 @@ func (_m *Repository) Find(_a0 context.Context, _a1 *domain.ListAppealsFilter) ( } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *domain.ListAppealsFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -89,8 +97,8 @@ type Repository_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.ListAppealsFilter +// - _a0 context.Context +// - _a1 *domain.ListAppealsFilter func (_e *Repository_Expecter) Find(_a0 interface{}, _a1 interface{}) *Repository_Find_Call { return &Repository_Find_Call{Call: _e.mock.On("Find", _a0, _a1)} } @@ -107,11 +115,73 @@ func (_c *Repository_Find_Call) Return(_a0 []*domain.Appeal, _a1 error) *Reposit return _c } +func (_c *Repository_Find_Call) RunAndReturn(run func(context.Context, *domain.ListAppealsFilter) ([]*domain.Appeal, error)) *Repository_Find_Call { + _c.Call.Return(run) + return _c +} + +// GetAppealsTotalCount provides a mock function with given fields: _a0, _a1 +func (_m *Repository) GetAppealsTotalCount(_a0 context.Context, _a1 *domain.ListAppealsFilter) (int64, error) { + ret := _m.Called(_a0, _a1) + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *domain.ListAppealsFilter) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *domain.ListAppealsFilter) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Repository_GetAppealsTotalCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAppealsTotalCount' +type Repository_GetAppealsTotalCount_Call struct { + *mock.Call +} + +// GetAppealsTotalCount is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *domain.ListAppealsFilter +func (_e *Repository_Expecter) GetAppealsTotalCount(_a0 interface{}, _a1 interface{}) *Repository_GetAppealsTotalCount_Call { + return &Repository_GetAppealsTotalCount_Call{Call: _e.mock.On("GetAppealsTotalCount", _a0, _a1)} +} + +func (_c *Repository_GetAppealsTotalCount_Call) Run(run func(_a0 context.Context, _a1 *domain.ListAppealsFilter)) *Repository_GetAppealsTotalCount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*domain.ListAppealsFilter)) + }) + return _c +} + +func (_c *Repository_GetAppealsTotalCount_Call) Return(_a0 int64, _a1 error) *Repository_GetAppealsTotalCount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Repository_GetAppealsTotalCount_Call) RunAndReturn(run func(context.Context, *domain.ListAppealsFilter) (int64, error)) *Repository_GetAppealsTotalCount_Call { + _c.Call.Return(run) + return _c +} + // GetByID provides a mock function with given fields: ctx, id func (_m *Repository) GetByID(ctx context.Context, id string) (*domain.Appeal, error) { ret := _m.Called(ctx, id) var r0 *domain.Appeal + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Appeal, error)); ok { + return rf(ctx, id) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Appeal); ok { r0 = rf(ctx, id) } else { @@ -120,7 +190,6 @@ func (_m *Repository) GetByID(ctx context.Context, id string) (*domain.Appeal, e } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, id) } else { @@ -136,8 +205,8 @@ type Repository_GetByID_Call struct { } // GetByID is a helper method to define mock.On call -// - ctx context.Context -// - id string +// - ctx context.Context +// - id string func (_e *Repository_Expecter) GetByID(ctx interface{}, id interface{}) *Repository_GetByID_Call { return &Repository_GetByID_Call{Call: _e.mock.On("GetByID", ctx, id)} } @@ -154,6 +223,11 @@ func (_c *Repository_GetByID_Call) Return(_a0 *domain.Appeal, _a1 error) *Reposi return _c } +func (_c *Repository_GetByID_Call) RunAndReturn(run func(context.Context, string) (*domain.Appeal, error)) *Repository_GetByID_Call { + _c.Call.Return(run) + return _c +} + // Update provides a mock function with given fields: _a0, _a1 func (_m *Repository) Update(_a0 context.Context, _a1 *domain.Appeal) error { ret := _m.Called(_a0, _a1) @@ -174,8 +248,8 @@ type Repository_Update_Call struct { } // Update is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Appeal +// - _a0 context.Context +// - _a1 *domain.Appeal func (_e *Repository_Expecter) Update(_a0 interface{}, _a1 interface{}) *Repository_Update_Call { return &Repository_Update_Call{Call: _e.mock.On("Update", _a0, _a1)} } @@ -191,3 +265,22 @@ func (_c *Repository_Update_Call) Return(_a0 error) *Repository_Update_Call { _c.Call.Return(_a0) return _c } + +func (_c *Repository_Update_Call) RunAndReturn(run func(context.Context, *domain.Appeal) error) *Repository_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewRepository creates a new instance of Repository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *Repository { + mock := &Repository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/mocks/resourceService.go b/core/appeal/mocks/resourceService.go index 38713699b..a801283cf 100644 --- a/core/appeal/mocks/resourceService.go +++ b/core/appeal/mocks/resourceService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *ResourceService) Find(_a0 context.Context, _a1 domain.ListResourcesFil ret := _m.Called(_a0, _a1) var r0 []*domain.Resource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListResourcesFilter) []*domain.Resource); ok { r0 = rf(_a0, _a1) } else { @@ -35,7 +39,6 @@ func (_m *ResourceService) Find(_a0 context.Context, _a1 domain.ListResourcesFil } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListResourcesFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -51,8 +54,8 @@ type ResourceService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ListResourcesFilter +// - _a0 context.Context +// - _a1 domain.ListResourcesFilter func (_e *ResourceService_Expecter) Find(_a0 interface{}, _a1 interface{}) *ResourceService_Find_Call { return &ResourceService_Find_Call{Call: _e.mock.On("Find", _a0, _a1)} } @@ -69,11 +72,20 @@ func (_c *ResourceService_Find_Call) Return(_a0 []*domain.Resource, _a1 error) * return _c } +func (_c *ResourceService_Find_Call) RunAndReturn(run func(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error)) *ResourceService_Find_Call { + _c.Call.Return(run) + return _c +} + // Get provides a mock function with given fields: _a0, _a1 func (_m *ResourceService) Get(_a0 context.Context, _a1 *domain.ResourceIdentifier) (*domain.Resource, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Resource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.ResourceIdentifier) (*domain.Resource, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *domain.ResourceIdentifier) *domain.Resource); ok { r0 = rf(_a0, _a1) } else { @@ -82,7 +94,6 @@ func (_m *ResourceService) Get(_a0 context.Context, _a1 *domain.ResourceIdentifi } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *domain.ResourceIdentifier) error); ok { r1 = rf(_a0, _a1) } else { @@ -98,8 +109,8 @@ type ResourceService_Get_Call struct { } // Get is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.ResourceIdentifier +// - _a0 context.Context +// - _a1 *domain.ResourceIdentifier func (_e *ResourceService_Expecter) Get(_a0 interface{}, _a1 interface{}) *ResourceService_Get_Call { return &ResourceService_Get_Call{Call: _e.mock.On("Get", _a0, _a1)} } @@ -115,3 +126,22 @@ func (_c *ResourceService_Get_Call) Return(_a0 *domain.Resource, _a1 error) *Res _c.Call.Return(_a0, _a1) return _c } + +func (_c *ResourceService_Get_Call) RunAndReturn(run func(context.Context, *domain.ResourceIdentifier) (*domain.Resource, error)) *ResourceService_Get_Call { + _c.Call.Return(run) + return _c +} + +// NewResourceService creates a new instance of ResourceService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewResourceService(t interface { + mock.TestingT + Cleanup(func()) +}) *ResourceService { + mock := &ResourceService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/appeal/service.go b/core/appeal/service.go index ffba964ef..9b30f976e 100644 --- a/core/appeal/service.go +++ b/core/appeal/service.go @@ -38,6 +38,7 @@ type repository interface { Find(context.Context, *domain.ListAppealsFilter) ([]*domain.Appeal, error) GetByID(ctx context.Context, id string) (*domain.Appeal, error) Update(context.Context, *domain.Appeal) error + GetAppealsTotalCount(context.Context, *domain.ListAppealsFilter) (int64, error) } //go:generate mockery --name=iamManager --exported --with-expecter @@ -1221,3 +1222,7 @@ func (s *Service) prepareGrant(ctx context.Context, appeal *domain.Appeal) (newG return grant, deactivatedGrant, nil } + +func (s *Service) GetAppealsTotalCount(ctx context.Context, filters *domain.ListAppealsFilter) (int64, error) { + return s.repo.GetAppealsTotalCount(ctx, filters) +} diff --git a/core/appeal/service_test.go b/core/appeal/service_test.go index c448d97db..3481f871c 100644 --- a/core/appeal/service_test.go +++ b/core/appeal/service_test.go @@ -2871,6 +2871,32 @@ func (s *ServiceTestSuite) TestDeleteApprover() { }) } +func (s *ServiceTestSuite) TestGetAppealsTotalCount() { + s.Run("should return error if got error from repository", func() { + expectedError := errors.New("repository error") + s.mockRepository.EXPECT(). + GetAppealsTotalCount(mock.AnythingOfType("*context.emptyCtx"), mock.Anything). + Return(0, expectedError).Once() + + actualCount, actualError := s.service.GetAppealsTotalCount(context.Background(), &domain.ListAppealsFilter{}) + + s.Zero(actualCount) + s.EqualError(actualError, expectedError.Error()) + }) + + s.Run("should return appeals count from repository", func() { + expectedCount := int64(1) + s.mockRepository.EXPECT(). + GetAppealsTotalCount(mock.AnythingOfType("*context.emptyCtx"), mock.Anything). + Return(expectedCount, nil).Once() + + actualCount, actualError := s.service.GetAppealsTotalCount(context.Background(), &domain.ListAppealsFilter{}) + + s.Equal(expectedCount, actualCount) + s.NoError(actualError) + }) +} + func TestService(t *testing.T) { suite.Run(t, new(ServiceTestSuite)) } diff --git a/core/grant/mocks/auditLogger.go b/core/grant/mocks/auditLogger.go index 421d831ee..d13bf9441 100644 --- a/core/grant/mocks/auditLogger.go +++ b/core/grant/mocks/auditLogger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -41,9 +41,9 @@ type AuditLogger_Log_Call struct { } // Log is a helper method to define mock.On call -// - ctx context.Context -// - action string -// - data interface{} +// - ctx context.Context +// - action string +// - data interface{} func (_e *AuditLogger_Expecter) Log(ctx interface{}, action interface{}, data interface{}) *AuditLogger_Log_Call { return &AuditLogger_Log_Call{Call: _e.mock.On("Log", ctx, action, data)} } @@ -59,3 +59,22 @@ func (_c *AuditLogger_Log_Call) Return(_a0 error) *AuditLogger_Log_Call { _c.Call.Return(_a0) return _c } + +func (_c *AuditLogger_Log_Call) RunAndReturn(run func(context.Context, string, interface{}) error) *AuditLogger_Log_Call { + _c.Call.Return(run) + return _c +} + +// NewAuditLogger creates a new instance of AuditLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAuditLogger(t interface { + mock.TestingT + Cleanup(func()) +}) *AuditLogger { + mock := &AuditLogger{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/grant/mocks/notifier.go b/core/grant/mocks/notifier.go index 4d5e3ee59..39d658ad2 100644 --- a/core/grant/mocks/notifier.go +++ b/core/grant/mocks/notifier.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -43,7 +43,7 @@ type Notifier_Notify_Call struct { } // Notify is a helper method to define mock.On call -// - _a0 []domain.Notification +// - _a0 []domain.Notification func (_e *Notifier_Expecter) Notify(_a0 interface{}) *Notifier_Notify_Call { return &Notifier_Notify_Call{Call: _e.mock.On("Notify", _a0)} } @@ -59,3 +59,22 @@ func (_c *Notifier_Notify_Call) Return(_a0 []error) *Notifier_Notify_Call { _c.Call.Return(_a0) return _c } + +func (_c *Notifier_Notify_Call) RunAndReturn(run func([]domain.Notification) []error) *Notifier_Notify_Call { + _c.Call.Return(run) + return _c +} + +// NewNotifier creates a new instance of Notifier. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewNotifier(t interface { + mock.TestingT + Cleanup(func()) +}) *Notifier { + mock := &Notifier{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/grant/mocks/providerService.go b/core/grant/mocks/providerService.go index 71cda6604..4d794400a 100644 --- a/core/grant/mocks/providerService.go +++ b/core/grant/mocks/providerService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -278,13 +278,12 @@ func (_c *ProviderService_RevokeAccess_Call) RunAndReturn(run func(context.Conte return _c } -type mockConstructorTestingTNewProviderService interface { +// NewProviderService creates a new instance of ProviderService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProviderService(t interface { mock.TestingT Cleanup(func()) -} - -// NewProviderService creates a new instance of ProviderService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewProviderService(t mockConstructorTestingTNewProviderService) *ProviderService { +}) *ProviderService { mock := &ProviderService{} mock.Mock.Test(t) diff --git a/core/grant/mocks/repository.go b/core/grant/mocks/repository.go index 730fa8f6d..6f9f8e3c5 100644 --- a/core/grant/mocks/repository.go +++ b/core/grant/mocks/repository.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -43,8 +43,8 @@ type Repository_BulkUpsert_Call struct { } // BulkUpsert is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 []*domain.Grant +// - _a0 context.Context +// - _a1 []*domain.Grant func (_e *Repository_Expecter) BulkUpsert(_a0 interface{}, _a1 interface{}) *Repository_BulkUpsert_Call { return &Repository_BulkUpsert_Call{Call: _e.mock.On("BulkUpsert", _a0, _a1)} } @@ -61,11 +61,20 @@ func (_c *Repository_BulkUpsert_Call) Return(_a0 error) *Repository_BulkUpsert_C return _c } +func (_c *Repository_BulkUpsert_Call) RunAndReturn(run func(context.Context, []*domain.Grant) error) *Repository_BulkUpsert_Call { + _c.Call.Return(run) + return _c +} + // GetByID provides a mock function with given fields: _a0, _a1 func (_m *Repository) GetByID(_a0 context.Context, _a1 string) (*domain.Grant, error) { ret := _m.Called(_a0, _a1) var r0 *domain.Grant + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*domain.Grant, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, string) *domain.Grant); ok { r0 = rf(_a0, _a1) } else { @@ -74,7 +83,6 @@ func (_m *Repository) GetByID(_a0 context.Context, _a1 string) (*domain.Grant, e } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(_a0, _a1) } else { @@ -90,8 +98,8 @@ type Repository_GetByID_Call struct { } // GetByID is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string +// - _a0 context.Context +// - _a1 string func (_e *Repository_Expecter) GetByID(_a0 interface{}, _a1 interface{}) *Repository_GetByID_Call { return &Repository_GetByID_Call{Call: _e.mock.On("GetByID", _a0, _a1)} } @@ -108,11 +116,73 @@ func (_c *Repository_GetByID_Call) Return(_a0 *domain.Grant, _a1 error) *Reposit return _c } +func (_c *Repository_GetByID_Call) RunAndReturn(run func(context.Context, string) (*domain.Grant, error)) *Repository_GetByID_Call { + _c.Call.Return(run) + return _c +} + +// GetGrantsTotalCount provides a mock function with given fields: _a0, _a1 +func (_m *Repository) GetGrantsTotalCount(_a0 context.Context, _a1 domain.ListGrantsFilter) (int64, error) { + ret := _m.Called(_a0, _a1) + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, domain.ListGrantsFilter) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Repository_GetGrantsTotalCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGrantsTotalCount' +type Repository_GetGrantsTotalCount_Call struct { + *mock.Call +} + +// GetGrantsTotalCount is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 domain.ListGrantsFilter +func (_e *Repository_Expecter) GetGrantsTotalCount(_a0 interface{}, _a1 interface{}) *Repository_GetGrantsTotalCount_Call { + return &Repository_GetGrantsTotalCount_Call{Call: _e.mock.On("GetGrantsTotalCount", _a0, _a1)} +} + +func (_c *Repository_GetGrantsTotalCount_Call) Run(run func(_a0 context.Context, _a1 domain.ListGrantsFilter)) *Repository_GetGrantsTotalCount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(domain.ListGrantsFilter)) + }) + return _c +} + +func (_c *Repository_GetGrantsTotalCount_Call) Return(_a0 int64, _a1 error) *Repository_GetGrantsTotalCount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Repository_GetGrantsTotalCount_Call) RunAndReturn(run func(context.Context, domain.ListGrantsFilter) (int64, error)) *Repository_GetGrantsTotalCount_Call { + _c.Call.Return(run) + return _c +} + // List provides a mock function with given fields: _a0, _a1 func (_m *Repository) List(_a0 context.Context, _a1 domain.ListGrantsFilter) ([]domain.Grant, error) { ret := _m.Called(_a0, _a1) var r0 []domain.Grant + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) ([]domain.Grant, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListGrantsFilter) []domain.Grant); ok { r0 = rf(_a0, _a1) } else { @@ -121,7 +191,6 @@ func (_m *Repository) List(_a0 context.Context, _a1 domain.ListGrantsFilter) ([] } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListGrantsFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -137,8 +206,8 @@ type Repository_List_Call struct { } // List is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ListGrantsFilter +// - _a0 context.Context +// - _a1 domain.ListGrantsFilter func (_e *Repository_Expecter) List(_a0 interface{}, _a1 interface{}) *Repository_List_Call { return &Repository_List_Call{Call: _e.mock.On("List", _a0, _a1)} } @@ -155,6 +224,11 @@ func (_c *Repository_List_Call) Return(_a0 []domain.Grant, _a1 error) *Repositor return _c } +func (_c *Repository_List_Call) RunAndReturn(run func(context.Context, domain.ListGrantsFilter) ([]domain.Grant, error)) *Repository_List_Call { + _c.Call.Return(run) + return _c +} + // Update provides a mock function with given fields: _a0, _a1 func (_m *Repository) Update(_a0 context.Context, _a1 *domain.Grant) error { ret := _m.Called(_a0, _a1) @@ -175,8 +249,8 @@ type Repository_Update_Call struct { } // Update is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *domain.Grant +// - _a0 context.Context +// - _a1 *domain.Grant func (_e *Repository_Expecter) Update(_a0 interface{}, _a1 interface{}) *Repository_Update_Call { return &Repository_Update_Call{Call: _e.mock.On("Update", _a0, _a1)} } @@ -192,3 +266,22 @@ func (_c *Repository_Update_Call) Return(_a0 error) *Repository_Update_Call { _c.Call.Return(_a0) return _c } + +func (_c *Repository_Update_Call) RunAndReturn(run func(context.Context, *domain.Grant) error) *Repository_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewRepository creates a new instance of Repository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *Repository { + mock := &Repository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/grant/mocks/resourceService.go b/core/grant/mocks/resourceService.go index dfb8264a5..ae9de1c15 100644 --- a/core/grant/mocks/resourceService.go +++ b/core/grant/mocks/resourceService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.33.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ func (_m *ResourceService) Find(_a0 context.Context, _a1 domain.ListResourcesFil ret := _m.Called(_a0, _a1) var r0 []*domain.Resource + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, domain.ListResourcesFilter) []*domain.Resource); ok { r0 = rf(_a0, _a1) } else { @@ -36,7 +40,6 @@ func (_m *ResourceService) Find(_a0 context.Context, _a1 domain.ListResourcesFil } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, domain.ListResourcesFilter) error); ok { r1 = rf(_a0, _a1) } else { @@ -52,8 +55,8 @@ type ResourceService_Find_Call struct { } // Find is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 domain.ListResourcesFilter +// - _a0 context.Context +// - _a1 domain.ListResourcesFilter func (_e *ResourceService_Expecter) Find(_a0 interface{}, _a1 interface{}) *ResourceService_Find_Call { return &ResourceService_Find_Call{Call: _e.mock.On("Find", _a0, _a1)} } @@ -69,3 +72,22 @@ func (_c *ResourceService_Find_Call) Return(_a0 []*domain.Resource, _a1 error) * _c.Call.Return(_a0, _a1) return _c } + +func (_c *ResourceService_Find_Call) RunAndReturn(run func(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error)) *ResourceService_Find_Call { + _c.Call.Return(run) + return _c +} + +// NewResourceService creates a new instance of ResourceService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewResourceService(t interface { + mock.TestingT + Cleanup(func()) +}) *ResourceService { + mock := &ResourceService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/grant/service.go b/core/grant/service.go index 74f6161b3..fc5573fc1 100644 --- a/core/grant/service.go +++ b/core/grant/service.go @@ -26,6 +26,7 @@ type repository interface { GetByID(context.Context, string) (*domain.Grant, error) Update(context.Context, *domain.Grant) error BulkUpsert(context.Context, []*domain.Grant) error + GetGrantsTotalCount(context.Context, domain.ListGrantsFilter) (int64, error) } //go:generate mockery --name=providerService --exported --with-expecter @@ -668,3 +669,7 @@ func getGrantIDs(grants []domain.Grant) []string { } return ids } + +func (s *Service) GetGrantsTotalCount(ctx context.Context, filters domain.ListGrantsFilter) (int64, error) { + return s.repo.GetGrantsTotalCount(ctx, filters) +} diff --git a/core/grant/service_test.go b/core/grant/service_test.go index 82ab4f249..2c96d862b 100644 --- a/core/grant/service_test.go +++ b/core/grant/service_test.go @@ -989,3 +989,29 @@ func (s *ServiceTestSuite) TestDormancyCheck() { s.NoError(err) }) } + +func (s *ServiceTestSuite) TestGetGrantsTotalCount() { + s.Run("should return error if got error from repository", func() { + expectedError := errors.New("repository error") + s.mockRepository.EXPECT(). + GetGrantsTotalCount(mock.AnythingOfType("*context.emptyCtx"), mock.Anything). + Return(0, expectedError).Once() + + actualCount, actualError := s.service.GetGrantsTotalCount(context.Background(), domain.ListGrantsFilter{}) + + s.Zero(actualCount) + s.EqualError(actualError, expectedError.Error()) + }) + + s.Run("should return Grants count from repository", func() { + expectedCount := int64(1) + s.mockRepository.EXPECT(). + GetGrantsTotalCount(mock.AnythingOfType("*context.emptyCtx"), mock.Anything). + Return(expectedCount, nil).Once() + + actualCount, actualError := s.service.GetGrantsTotalCount(context.Background(), domain.ListGrantsFilter{}) + + s.Equal(expectedCount, actualCount) + s.NoError(actualError) + }) +} diff --git a/domain/appeal.go b/domain/appeal.go index 87349dad2..cb455f939 100644 --- a/domain/appeal.go +++ b/domain/appeal.go @@ -277,6 +277,8 @@ type ApprovalAction struct { } type ListAppealsFilter struct { + Q string `mapstructure:"q" validate:"omitempty"` + AccountTypes []string `mapstructure:"account_types" validate:"omitempty,min=1"` CreatedBy string `mapstructure:"created_by" validate:"omitempty,required"` AccountID string `mapstructure:"account_id" validate:"omitempty,required"` AccountIDs []string `mapstructure:"account_ids" validate:"omitempty,required"` diff --git a/domain/grant.go b/domain/grant.go index 84fdbeed4..09759961e 100644 --- a/domain/grant.go +++ b/domain/grant.go @@ -104,8 +104,9 @@ type ListGrantsFilter struct { ExpirationDateGreaterThan time.Time IsPermanent *bool CreatedAtLte time.Time - Size int `mapstructure:"size" validate:"omitempty"` - Offset int `mapstructure:"offset" validate:"omitempty"` + Size int `mapstructure:"size" validate:"omitempty"` + Offset int `mapstructure:"offset" validate:"omitempty"` + Q string `mapstructure:"q" validate:"omitempty"` } type RevokeGrantsFilter struct { diff --git a/internal/store/postgres/appeal_repository.go b/internal/store/postgres/appeal_repository.go index 45fc71a03..7aba18cfd 100644 --- a/internal/store/postgres/appeal_repository.go +++ b/internal/store/postgres/appeal_repository.go @@ -65,60 +65,7 @@ func (r *AppealRepository) Find(ctx context.Context, filters *domain.ListAppeals } db := r.db.WithContext(ctx) - if filters.Size > 0 { - db = db.Limit(filters.Size) - } - if filters.Offset > 0 { - db = db.Offset(filters.Offset) - } - if filters.CreatedBy != "" { - db = db.Where(`"appeals"."created_by" = ?`, filters.CreatedBy) - } - accounts := make([]string, 0) - if filters.AccountID != "" { - accounts = append(accounts, filters.AccountID) - } - if filters.AccountIDs != nil { - accounts = append(accounts, filters.AccountIDs...) - } - if len(accounts) > 0 { - db = db.Where(`"appeals"."account_id" IN ?`, accounts) - } - if filters.Statuses != nil { - db = db.Where(`"appeals"."status" IN ?`, filters.Statuses) - } - if filters.ResourceID != "" { - db = db.Where(`"appeals"."resource_id" = ?`, filters.ResourceID) - } - if filters.Role != "" { - db = db.Where(`"appeals"."role" = ?`, filters.Role) - } - if !filters.ExpirationDateLessThan.IsZero() { - db = db.Where(`"options" -> 'expiration_date' < ?`, filters.ExpirationDateLessThan) - } - if !filters.ExpirationDateGreaterThan.IsZero() { - db = db.Where(`"options" -> 'expiration_date' > ?`, filters.ExpirationDateGreaterThan) - } - if filters.OrderBy != nil { - db = addOrderByClause(db, filters.OrderBy, addOrderByClauseOptions{ - statusColumnName: `"appeals"."status"`, - statusesOrder: AppealStatusDefaultSort, - }) - } - - db = db.Joins("Resource") - if filters.ProviderTypes != nil { - db = db.Where(`"Resource"."provider_type" IN ?`, filters.ProviderTypes) - } - if filters.ProviderURNs != nil { - db = db.Where(`"Resource"."provider_urn" IN ?`, filters.ProviderURNs) - } - if filters.ResourceTypes != nil { - db = db.Where(`"Resource"."type" IN ?`, filters.ResourceTypes) - } - if filters.ResourceURNs != nil { - db = db.Where(`"Resource"."urn" IN ?`, filters.ResourceURNs) - } + db = applyAppealFilter(db, filters) var models []*model.Appeal if err := db.Joins("Grant").Find(&models).Error; err != nil { @@ -138,6 +85,15 @@ func (r *AppealRepository) Find(ctx context.Context, filters *domain.ListAppeals return records, nil } +func (r *AppealRepository) GetAppealsTotalCount(ctx context.Context, filter *domain.ListAppealsFilter) (int64, error) { + db := r.db.WithContext(ctx) + db = applyAppealFilter(db, filter) + var count int64 + err := db.Model(&model.Appeal{}).Count(&count).Error + + return count, err +} + // BulkUpsert new record to database func (r *AppealRepository) BulkUpsert(ctx context.Context, appeals []*domain.Appeal) error { models := []*model.Appeal{} @@ -192,3 +148,81 @@ func (r *AppealRepository) Update(ctx context.Context, a *domain.Appeal) error { return nil }) } + +func applyAppealFilter(db *gorm.DB, filters *domain.ListAppealsFilter) *gorm.DB { + db = db.Joins("JOIN resources ON appeals.resource_id = resources.id") + if filters.Q != "" { + // NOTE: avoid adding conditions before this grouped where clause. + // Otherwise, it will be wrapped in parentheses and the query will be invalid. + db = db.Where(db. + Where(`"appeals"."account_id" LIKE ?`, fmt.Sprintf("%%%s%%", filters.Q)). + Or(`"appeals"."role" LIKE ?`, fmt.Sprintf("%%%s%%", filters.Q)). + Or(`"resources"."urn" LIKE ?`, fmt.Sprintf("%%%s%%", filters.Q)), + ) + } + if filters.Statuses != nil { + db = db.Where(`"appeals"."status" IN ?`, filters.Statuses) + } + if filters.AccountTypes != nil { + db = db.Where(`"appeals"."account_type" IN ?`, filters.AccountTypes) + } + if filters.ResourceTypes != nil { + db = db.Where(`"resources"."type" IN ?`, filters.ResourceTypes) + } + if filters.Size > 0 { + db = db.Limit(filters.Size) + } + if filters.Offset > 0 { + db = db.Offset(filters.Offset) + } + if filters.CreatedBy != "" { + db = db.Where(`"appeals"."created_by" = ?`, filters.CreatedBy) + } + accounts := make([]string, 0) + if filters.AccountID != "" { + accounts = append(accounts, filters.AccountID) + } + if filters.AccountIDs != nil { + accounts = append(accounts, filters.AccountIDs...) + } + if len(accounts) > 0 { + db = db.Where(`"appeals"."account_id" IN ?`, accounts) + } + if filters.Statuses != nil { + db = db.Where(`"appeals"."status" IN ?`, filters.Statuses) + } + if filters.ResourceID != "" { + db = db.Where(`"appeals"."resource_id" = ?`, filters.ResourceID) + } + if filters.Role != "" { + db = db.Where(`"appeals"."role" = ?`, filters.Role) + } + if !filters.ExpirationDateLessThan.IsZero() { + db = db.Where(`"options" -> 'expiration_date' < ?`, filters.ExpirationDateLessThan) + } + if !filters.ExpirationDateGreaterThan.IsZero() { + db = db.Where(`"options" -> 'expiration_date' > ?`, filters.ExpirationDateGreaterThan) + } + if filters.OrderBy != nil { + db = addOrderByClause(db, filters.OrderBy, addOrderByClauseOptions{ + statusColumnName: `"appeals"."status"`, + statusesOrder: AppealStatusDefaultSort, + }) + } + + db = db.Joins("Resource") + if filters.ProviderTypes != nil { + db = db.Where(`"Resource"."provider_type" IN ?`, filters.ProviderTypes) + } + if filters.ProviderURNs != nil { + db = db.Where(`"Resource"."provider_urn" IN ?`, filters.ProviderURNs) + } + if filters.ResourceTypes != nil { + db = db.Where(`"Resource"."type" IN ?`, filters.ResourceTypes) + } + if filters.ResourceURNs != nil { + db = db.Where(`"Resource"."urn" IN ?`, filters.ResourceURNs) + } + + return db +} diff --git a/internal/store/postgres/appeal_repository_test.go b/internal/store/postgres/appeal_repository_test.go index 242f02ea6..2e4f4c1f1 100644 --- a/internal/store/postgres/appeal_repository_test.go +++ b/internal/store/postgres/appeal_repository_test.go @@ -128,6 +128,70 @@ func (s *AppealRepositoryTestSuite) TestGetByID() { s.Nil(actualError) s.Equal(dummyAppeal.ID, actualRecord.ID) }) + + s.Run("should run query based on filters", func() { + timeNowPlusAnHour := time.Now().Add(time.Hour) + dummyAppeals := []*domain.Appeal{ + { + ResourceID: s.dummyResource.ID, + PolicyID: s.dummyPolicy.ID, + PolicyVersion: s.dummyPolicy.Version, + AccountID: "user@example.com", + AccountType: domain.DefaultAppealAccountType, + Role: "role_test", + Status: domain.AppealStatusApproved, + Permissions: []string{"permission_test"}, + CreatedBy: "user@example.com", + Options: &domain.AppealOptions{ + ExpirationDate: &time.Time{}, + }, + }, + { + ResourceID: s.dummyResource.ID, + PolicyID: s.dummyPolicy.ID, + PolicyVersion: s.dummyPolicy.Version, + AccountID: "user2@example.com", + AccountType: domain.DefaultAppealAccountType, + Status: domain.AppealStatusCanceled, + Role: "role_test", + Permissions: []string{"permission_test_2"}, + CreatedBy: "user2@example.com", + Options: &domain.AppealOptions{ + ExpirationDate: &timeNowPlusAnHour, + }, + }, + } + testCases := []struct { + filters *domain.ListAppealsFilter + expectedArgs []driver.Value + expectedResult []*domain.Appeal + }{ + { + filters: &domain.ListAppealsFilter{ + Q: "user", + }, + expectedResult: []*domain.Appeal{dummyAppeals[0], dummyAppeals[1]}, + }, + { + filters: &domain.ListAppealsFilter{ + AccountTypes: []string{"x-account-type"}, + }, + expectedResult: []*domain.Appeal{dummyAppeals[0], dummyAppeals[1]}, + }, + } + + for _, tc := range testCases { + _, actualError := s.repository.Find(context.Background(), tc.filters) + s.Nil(actualError) + } + }) +} + +func (s *AppealRepositoryTestSuite) TestGetAppealsTotalCount() { + s.Run("should return 0", func() { + _, actualError := s.repository.GetAppealsTotalCount(context.Background(), &domain.ListAppealsFilter{}) + s.Nil(actualError) + }) } func (s *AppealRepositoryTestSuite) TestFind() { @@ -283,6 +347,18 @@ func (s *AppealRepositoryTestSuite) TestFind() { }, expectedResult: []*domain.Appeal{dummyAppeals[1], dummyAppeals[0]}, }, + { + filters: &domain.ListAppealsFilter{ + Q: "user", + }, + expectedResult: []*domain.Appeal{dummyAppeals[1], dummyAppeals[0]}, + }, + { + filters: &domain.ListAppealsFilter{ + AccountTypes: []string{"x-account-type"}, + }, + expectedResult: []*domain.Appeal{dummyAppeals[1], dummyAppeals[0]}, + }, } for _, tc := range testCases { @@ -315,7 +391,6 @@ func (s *AppealRepositoryTestSuite) TestFind() { _, actualError := s.repository.Find(context.Background(), tc.filters) s.Nil(actualError) } - }) } diff --git a/internal/store/postgres/approval_repository_test.go b/internal/store/postgres/approval_repository_test.go index 458d39937..0e10fc16c 100644 --- a/internal/store/postgres/approval_repository_test.go +++ b/internal/store/postgres/approval_repository_test.go @@ -117,6 +117,14 @@ func (s *ApprovalRepositoryTestSuite) TearDownSuite() { } } +func (s *ApprovalRepositoryTestSuite) TestGetApprovalsTotalCount() { + + s.Run("should return 0", func() { + _, actualError := s.repository.GetApprovalsTotalCount(context.Background(), &domain.ListApprovalsFilter{}) + s.Nil(actualError) + }) +} + func (s *ApprovalRepositoryTestSuite) TestListApprovals() { pendingAppeal := &domain.Appeal{ ResourceID: s.dummyResource.ID, diff --git a/internal/store/postgres/grant_repository.go b/internal/store/postgres/grant_repository.go index cb2a8a470..3191fd5f0 100644 --- a/internal/store/postgres/grant_repository.go +++ b/internal/store/postgres/grant_repository.go @@ -30,65 +30,7 @@ func NewGrantRepository(db *gorm.DB) *GrantRepository { func (r *GrantRepository) List(ctx context.Context, filter domain.ListGrantsFilter) ([]domain.Grant, error) { db := r.db.WithContext(ctx) - if filter.Size > 0 { - db = db.Limit(filter.Size) - } - if filter.Offset > 0 { - db = db.Offset(filter.Offset) - } - if filter.AccountIDs != nil { - db = db.Where(`"grants"."account_id" IN ?`, filter.AccountIDs) - } - if filter.AccountTypes != nil { - db = db.Where(`"grants"."account_type" IN ?`, filter.AccountTypes) - } - if filter.ResourceIDs != nil { - db = db.Where(`"grants"."resource_id" IN ?`, filter.ResourceIDs) - } - if filter.Statuses != nil { - db = db.Where(`"grants"."status" IN ?`, filter.Statuses) - } - if filter.Roles != nil { - db = db.Where(`"grants"."role" IN ?`, filter.Roles) - } - if filter.Permissions != nil { - db = db.Where(`"grants"."permissions" @> ?`, pq.StringArray(filter.Permissions)) - } - if filter.Owner != "" { - db = db.Where(`"grants"."owner" = ?`, filter.Owner) - } else if filter.CreatedBy != "" { - db = db.Where(`"grants"."owner" = ?`, filter.CreatedBy) - } - if filter.IsPermanent != nil { - db = db.Where(`"grants"."is_permanent" = ?`, *filter.IsPermanent) - } - if !filter.CreatedAtLte.IsZero() { - db = db.Where(`"grants"."created_at" <= ?`, filter.CreatedAtLte) - } - if filter.OrderBy != nil { - db = addOrderByClause(db, filter.OrderBy, addOrderByClauseOptions{ - statusColumnName: `"grants"."status"`, - statusesOrder: GrantStatusDefaultSort, - }) - } - if !filter.ExpirationDateLessThan.IsZero() { - db = db.Where(`"grants"."expiration_date" < ?`, filter.ExpirationDateLessThan) - } - if !filter.ExpirationDateGreaterThan.IsZero() { - db = db.Where(`"grants"."expiration_date" > ?`, filter.ExpirationDateGreaterThan) - } - if filter.ProviderTypes != nil { - db = db.Where(`"Resource"."provider_type" IN ?`, filter.ProviderTypes) - } - if filter.ProviderURNs != nil { - db = db.Where(`"Resource"."provider_urn" IN ?`, filter.ProviderURNs) - } - if filter.ResourceTypes != nil { - db = db.Where(`"Resource"."type" IN ?`, filter.ResourceTypes) - } - if filter.ResourceURNs != nil { - db = db.Where(`"Resource"."urn" IN ?`, filter.ResourceURNs) - } + db = applyGrantFilter(db, filter) var models []model.Grant if err := db.Joins("Resource").Joins("Appeal").Find(&models).Error; err != nil { @@ -107,6 +49,15 @@ func (r *GrantRepository) List(ctx context.Context, filter domain.ListGrantsFilt return grants, nil } +func (r *GrantRepository) GetGrantsTotalCount(ctx context.Context, filter domain.ListGrantsFilter) (int64, error) { + db := r.db.WithContext(ctx) + db = applyGrantFilter(db, filter) + var count int64 + err := db.Model(&model.Grant{}).Count(&count).Error + + return count, err +} + func (r *GrantRepository) GetByID(ctx context.Context, id string) (*domain.Grant, error) { m := new(model.Grant) if err := r.db.WithContext(ctx).Joins("Resource").Joins("Appeal").First(&m, `"grants"."id" = ?`, id).Error; err != nil { @@ -246,3 +197,76 @@ func upsertResources(tx *gorm.DB, models []*model.Grant) error { return nil } + +func applyGrantFilter(db *gorm.DB, filter domain.ListGrantsFilter) *gorm.DB { + db = db.Joins("JOIN resources ON grants.resource_id = resources.id") + if filter.Q != "" { + // NOTE: avoid adding conditions before this grouped where clause. + // Otherwise, it will be wrapped in parentheses and the query will be invalid. + db = db.Where(db. + Where(`"grants"."account_id" LIKE ?`, fmt.Sprintf("%%%s%%", filter.Q)). + Or(`"grants"."role" LIKE ?`, fmt.Sprintf("%%%s%%", filter.Q)). + Or(`"resources"."urn" LIKE ?`, fmt.Sprintf("%%%s%%", filter.Q)), + ) + } + if filter.Size > 0 { + db = db.Limit(filter.Size) + } + if filter.Offset > 0 { + db = db.Offset(filter.Offset) + } + if filter.AccountIDs != nil { + db = db.Where(`"grants"."account_id" IN ?`, filter.AccountIDs) + } + if filter.AccountTypes != nil { + db = db.Where(`"grants"."account_type" IN ?`, filter.AccountTypes) + } + if filter.ResourceIDs != nil { + db = db.Where(`"grants"."resource_id" IN ?`, filter.ResourceIDs) + } + if filter.Statuses != nil { + db = db.Where(`"grants"."status" IN ?`, filter.Statuses) + } + if filter.Roles != nil { + db = db.Where(`"grants"."role" IN ?`, filter.Roles) + } + if filter.Permissions != nil { + db = db.Where(`"grants"."permissions" @> ?`, pq.StringArray(filter.Permissions)) + } + if filter.Owner != "" { + db = db.Where(`"grants"."owner" = ?`, filter.Owner) + } else if filter.CreatedBy != "" { + db = db.Where(`"grants"."owner" = ?`, filter.CreatedBy) + } + if filter.IsPermanent != nil { + db = db.Where(`"grants"."is_permanent" = ?`, *filter.IsPermanent) + } + if !filter.CreatedAtLte.IsZero() { + db = db.Where(`"grants"."created_at" <= ?`, filter.CreatedAtLte) + } + if filter.OrderBy != nil { + db = addOrderByClause(db, filter.OrderBy, addOrderByClauseOptions{ + statusColumnName: `"grants"."status"`, + statusesOrder: GrantStatusDefaultSort, + }) + } + if !filter.ExpirationDateLessThan.IsZero() { + db = db.Where(`"grants"."expiration_date" < ?`, filter.ExpirationDateLessThan) + } + if !filter.ExpirationDateGreaterThan.IsZero() { + db = db.Where(`"grants"."expiration_date" > ?`, filter.ExpirationDateGreaterThan) + } + if filter.ProviderTypes != nil { + db = db.Where(`"Resource"."provider_type" IN ?`, filter.ProviderTypes) + } + if filter.ProviderURNs != nil { + db = db.Where(`"Resource"."provider_urn" IN ?`, filter.ProviderURNs) + } + if filter.ResourceTypes != nil { + db = db.Where(`"Resource"."type" IN ?`, filter.ResourceTypes) + } + if filter.ResourceURNs != nil { + db = db.Where(`"Resource"."urn" IN ?`, filter.ResourceURNs) + } + return db +} diff --git a/internal/store/postgres/grant_repository_test.go b/internal/store/postgres/grant_repository_test.go index e9bf8b2d3..7176f43b7 100644 --- a/internal/store/postgres/grant_repository_test.go +++ b/internal/store/postgres/grant_repository_test.go @@ -120,6 +120,13 @@ func (s *GrantRepositoryTestSuite) TearDownSuite() { } } +func (s *GrantRepositoryTestSuite) TestGetGrantsTotalCount() { + s.Run("should return 0", func() { + _, actualError := s.repository.GetGrantsTotalCount(context.Background(), domain.ListGrantsFilter{}) + + s.Nil(actualError) + }) +} func (s *GrantRepositoryTestSuite) TestList() { expDate := time.Now() dummyGrants := []*domain.Grant{ @@ -206,6 +213,22 @@ func (s *GrantRepositoryTestSuite) TestList() { } }) + + s.Run("Should return an array that matches q", func() { + grants, err := s.repository.List(context.Background(), domain.ListGrantsFilter{ + Q: "123", + }) + + s.NoError(err) + s.Len(grants, 0) + }) + s.Run("Should return an array of grants that matches account type", func() { + grants, err := s.repository.List(context.Background(), domain.ListGrantsFilter{ + AccountTypes: []string{"x-account-type"}, + }) + s.NoError(err) + s.Len(grants, 0) + }) } func (s *GrantRepositoryTestSuite) TestGetByID() { From 7023ec4d5c13107411d781336416443ee8d3710c Mon Sep 17 00:00:00 2001 From: Rahmat Hidayat Date: Thu, 31 Aug 2023 17:23:26 +0700 Subject: [PATCH 2/2] feat(gcloud_iam): manage service account access (#58) * feat: introduce new resource type "service_account" in gcloud_iam provider * feat: grant and revoke access to service account * test: add test cases for service account provider * refactor: use switch case * chore: user goreleaser v1.18.2 * chore: use goreleaser v1.8.3 * chore: fix release pipeline * fix: fix fetching grantable roles next page token * refactor: remove additional checking * chore: use email as service account resource name * test: add more unit tests for GetResources * test: add more unit tests for Grant and Revoke Access --- plugins/providers/gcloudiam/client.go | 144 +++-- plugins/providers/gcloudiam/config.go | 60 +- .../gcloudiam/mocks/GcloudIamClient.go | 248 +++++++- plugins/providers/gcloudiam/provider.go | 120 ++-- plugins/providers/gcloudiam/provider_test.go | 549 ++++++++++++++---- plugins/providers/gcloudiam/resource.go | 5 +- 6 files changed, 862 insertions(+), 264 deletions(-) diff --git a/plugins/providers/gcloudiam/client.go b/plugins/providers/gcloudiam/client.go index 8aab12d24..fff88dc5c 100644 --- a/plugins/providers/gcloudiam/client.go +++ b/plugins/providers/gcloudiam/client.go @@ -41,42 +41,55 @@ func newIamClient(credentialsJSON []byte, resourceName string) (*iamClient, erro }, nil } -func (c *iamClient) GetRoles() ([]*Role, error) { - var roles []*Role +func (c *iamClient) ListServiceAccounts(ctx context.Context) ([]*iam.ServiceAccount, error) { + res, err := c.iamService.Projects.ServiceAccounts.List(c.resourceName).Context(ctx).Do() + if err != nil { + return nil, err + } + return res.Accounts, nil +} - ctx := context.TODO() - req := c.iamService.Roles.List() - if err := req.Pages(ctx, func(page *iam.ListRolesResponse) error { - for _, role := range page.Roles { - roles = append(roles, c.fromIamRole(role)) +func (c *iamClient) GetGrantableRoles(ctx context.Context, resourceType string) ([]*iam.Role, error) { + var fullResourceName string + switch resourceType { + case ResourceTypeOrganization: + orgID := strings.Replace(c.resourceName, ResourceNameOrganizationPrefix, "", 1) + fullResourceName = fmt.Sprintf("//cloudresourcemanager.googleapis.com/organizations/%s", orgID) + + case ResourceTypeProject: + projectID := strings.Replace(c.resourceName, ResourceNameProjectPrefix, "", 1) + fullResourceName = fmt.Sprintf("//cloudresourcemanager.googleapis.com/projects/%s", projectID) + + case ResourceTypeServiceAccount: + projectID := strings.Replace(c.resourceName, ResourceNameProjectPrefix, "", 1) + res, err := c.iamService.Projects.ServiceAccounts.List(c.resourceName).PageSize(1).Context(ctx).Do() + if err != nil { + return nil, fmt.Errorf("getting a sample of service account: %w", err) } - return nil - }); err != nil { - return nil, err + if res.Accounts == nil || len(res.Accounts) == 0 { + return nil, fmt.Errorf("no service accounts found in project %s", projectID) + } + fullResourceName = fmt.Sprintf("//iam.googleapis.com/%s", res.Accounts[0].Name) + + default: + return nil, fmt.Errorf("unknown resource type %s", resourceType) } - if strings.HasPrefix(c.resourceName, ResourceNameProjectPrefix) { - projectRolesReq := c.iamService.Projects.Roles.List(c.resourceName) - if err := projectRolesReq.Pages(ctx, func(page *iam.ListRolesResponse) error { - for _, role := range page.Roles { - roles = append(roles, c.fromIamRole(role)) - } - return nil - }); err != nil { - return nil, err + roles := []*iam.Role{} + nextPageToken := "" + for { + req := &iam.QueryGrantableRolesRequest{ + FullResourceName: fullResourceName, + PageToken: nextPageToken, } - } else if strings.HasPrefix(c.resourceName, ResourceNameOrganizationPrefix) { - orgRolesReq := c.iamService.Organizations.Roles.List(c.resourceName) - if err := orgRolesReq.Pages(ctx, func(page *iam.ListRolesResponse) error { - for _, role := range page.Roles { - roles = append(roles, c.fromIamRole(role)) - } - return nil - }); err != nil { + res, err := c.iamService.Roles.QueryGrantableRoles(req).Context(ctx).Do() + if err != nil { return nil, err } - } else { - return nil, ErrInvalidResourceName + roles = append(roles, res.Roles...) + if nextPageToken = res.NextPageToken; nextPageToken == "" { + break + } } return roles, nil @@ -138,6 +151,71 @@ func (c *iamClient) RevokeAccess(accountType, accountID, role string) error { return err } +func (c *iamClient) GrantServiceAccountAccess(ctx context.Context, sa, accountType, accountID, role string) error { + policy, err := c.iamService.Projects.ServiceAccounts. + GetIamPolicy(sa).Context(ctx).Do() + if err != nil { + return fmt.Errorf("getting IAM policy of service account %q: %w", sa, err) + } + + member := fmt.Sprintf("%s:%s", accountType, accountID) + roleExists := false + for _, b := range policy.Bindings { + if b.Role == role { + if containsString(b.Members, member) { + return ErrPermissionAlreadyExists + } + b.Members = append(b.Members, member) + } + } + if !roleExists { + policy.Bindings = append(policy.Bindings, &iam.Binding{ + Role: role, + Members: []string{member}, + }) + } + + if _, err := c.iamService.Projects.ServiceAccounts. + SetIamPolicy(sa, &iam.SetIamPolicyRequest{Policy: policy}). + Context(ctx).Do(); err != nil { + return fmt.Errorf("setting IAM policy of service account %q: %w", sa, err) + } + + return nil +} + +func (c *iamClient) RevokeServiceAccountAccess(ctx context.Context, sa, accountType, accountID, role string) error { + policy, err := c.iamService.Projects.ServiceAccounts. + GetIamPolicy(sa).Context(ctx).Do() + if err != nil { + return fmt.Errorf("getting IAM policy of service account %q: %w", sa, err) + } + + member := fmt.Sprintf("%s:%s", accountType, accountID) + for _, b := range policy.Bindings { + if b.Role == role { + removeIndex := -1 + for i, m := range b.Members { + if m == member { + removeIndex = i + } + } + if removeIndex == -1 { + return ErrPermissionNotFound + } + b.Members = append(b.Members[:removeIndex], b.Members[removeIndex+1:]...) + } + } + + if _, err := c.iamService.Projects.ServiceAccounts. + SetIamPolicy(sa, &iam.SetIamPolicyRequest{Policy: policy}). + Context(ctx).Do(); err != nil { + return fmt.Errorf("setting IAM policy of service account %q: %w", sa, err) + } + + return nil +} + func (c *iamClient) ListAccess(ctx context.Context, resources []*domain.Resource) (domain.MapResourceAccess, error) { policy, err := c.getIamPolicy(ctx) if err != nil { @@ -195,14 +273,6 @@ func (c *iamClient) setIamPolicy(ctx context.Context, policy *cloudresourcemanag return nil, ErrInvalidResourceName } -func (c *iamClient) fromIamRole(r *iam.Role) *Role { - return &Role{ - Name: r.Name, - Title: r.Title, - Description: r.Description, - } -} - func containsString(arr []string, v string) bool { for _, item := range arr { if item == v { diff --git a/plugins/providers/gcloudiam/config.go b/plugins/providers/gcloudiam/config.go index ca6942cca..2a08c63fa 100644 --- a/plugins/providers/gcloudiam/config.go +++ b/plugins/providers/gcloudiam/config.go @@ -1,6 +1,7 @@ package gcloudiam import ( + "context" "encoding/base64" "errors" "fmt" @@ -8,6 +9,7 @@ import ( "github.com/go-playground/validator/v10" "github.com/goto/guardian/domain" + "github.com/goto/guardian/utils" "github.com/mitchellh/mapstructure" ) @@ -102,12 +104,29 @@ func (c *Config) parseAndValidate() error { c.ProviderConfig.Credentials = credentials } - if len(c.ProviderConfig.Resources) != 1 { - return ErrShouldHaveOneResource + if c.ProviderConfig.Resources == nil || len(c.ProviderConfig.Resources) == 0 { + return errors.New("empty resource config") } - r := c.ProviderConfig.Resources[0] - if err := c.validateResourceConfig(r); err != nil { - validationErrors = append(validationErrors, err) + uniqueResourceTypes := make(map[string]bool) + for _, rc := range c.ProviderConfig.Resources { + if _, ok := uniqueResourceTypes[rc.Type]; ok { + validationErrors = append(validationErrors, fmt.Errorf("duplicate resource type: %q", rc.Type)) + } + uniqueResourceTypes[rc.Type] = true + + allowedResourceTypes := []string{} + if strings.HasPrefix(credentials.ResourceName, ResourceNameOrganizationPrefix) { + allowedResourceTypes = []string{ResourceTypeOrganization} + } else if strings.HasPrefix(credentials.ResourceName, ResourceNameProjectPrefix) { + allowedResourceTypes = []string{ResourceTypeProject, ResourceTypeServiceAccount} + } + if !utils.ContainsString(allowedResourceTypes, rc.Type) { + validationErrors = append(validationErrors, fmt.Errorf("invalid resource type: %q", rc.Type)) + } + + if len(rc.Roles) == 0 { + validationErrors = append(validationErrors, ErrRolesShouldNotBeEmpty) + } } if len(validationErrors) > 0 { @@ -142,37 +161,14 @@ func (c *Config) validateCredentials(value interface{}) (*Credentials, error) { return &credentials, nil } -func (c *Config) validateResourceConfig(resource *domain.ResourceConfig) error { - resourceTypeValidation := fmt.Sprintf("oneof=%s %s", ResourceTypeProject, ResourceTypeOrganization) - if err := c.validator.Var(resource.Type, resourceTypeValidation); err != nil { - return err - } - - if len(resource.Roles) == 0 { - return ErrRolesShouldNotBeEmpty - } - - return nil -} - func (c *Config) validatePermissions(resource *domain.ResourceConfig, client GcloudIamClient) error { - iamRoles, err := client.GetRoles() + iamRoles, err := client.GetGrantableRoles(context.TODO(), resource.Type) if err != nil { return err } - - var roles []*domain.Role - for _, r := range iamRoles { - roles = append(roles, &domain.Role{ - ID: r.Name, - Name: r.Title, - Description: r.Description, - }) - } - - rolesMap := make(map[string]*domain.Role) - for _, role := range roles { - rolesMap[role.ID] = role + rolesMap := make(map[string]bool) + for _, role := range iamRoles { + rolesMap[role.Name] = true } for _, ro := range resource.Roles { diff --git a/plugins/providers/gcloudiam/mocks/GcloudIamClient.go b/plugins/providers/gcloudiam/mocks/GcloudIamClient.go index ec9e0b1ee..8d687aea3 100644 --- a/plugins/providers/gcloudiam/mocks/GcloudIamClient.go +++ b/plugins/providers/gcloudiam/mocks/GcloudIamClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package mocks @@ -6,7 +6,8 @@ import ( context "context" domain "github.com/goto/guardian/domain" - gcloudiam "github.com/goto/guardian/plugins/providers/gcloudiam" + + iam "google.golang.org/api/iam/v1" mock "github.com/stretchr/testify/mock" ) @@ -24,22 +25,25 @@ func (_m *GcloudIamClient) EXPECT() *GcloudIamClient_Expecter { return &GcloudIamClient_Expecter{mock: &_m.Mock} } -// GetRoles provides a mock function with given fields: -func (_m *GcloudIamClient) GetRoles() ([]*gcloudiam.Role, error) { - ret := _m.Called() +// GetGrantableRoles provides a mock function with given fields: ctx, resourceType +func (_m *GcloudIamClient) GetGrantableRoles(ctx context.Context, resourceType string) ([]*iam.Role, error) { + ret := _m.Called(ctx, resourceType) - var r0 []*gcloudiam.Role - if rf, ok := ret.Get(0).(func() []*gcloudiam.Role); ok { - r0 = rf() + var r0 []*iam.Role + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]*iam.Role, error)); ok { + return rf(ctx, resourceType) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []*iam.Role); ok { + r0 = rf(ctx, resourceType) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*gcloudiam.Role) + r0 = ret.Get(0).([]*iam.Role) } } - var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, resourceType) } else { r1 = ret.Error(1) } @@ -47,28 +51,35 @@ func (_m *GcloudIamClient) GetRoles() ([]*gcloudiam.Role, error) { return r0, r1 } -// GcloudIamClient_GetRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRoles' -type GcloudIamClient_GetRoles_Call struct { +// GcloudIamClient_GetGrantableRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGrantableRoles' +type GcloudIamClient_GetGrantableRoles_Call struct { *mock.Call } -// GetRoles is a helper method to define mock.On call -func (_e *GcloudIamClient_Expecter) GetRoles() *GcloudIamClient_GetRoles_Call { - return &GcloudIamClient_GetRoles_Call{Call: _e.mock.On("GetRoles")} +// GetGrantableRoles is a helper method to define mock.On call +// - ctx context.Context +// - resourceType string +func (_e *GcloudIamClient_Expecter) GetGrantableRoles(ctx interface{}, resourceType interface{}) *GcloudIamClient_GetGrantableRoles_Call { + return &GcloudIamClient_GetGrantableRoles_Call{Call: _e.mock.On("GetGrantableRoles", ctx, resourceType)} } -func (_c *GcloudIamClient_GetRoles_Call) Run(run func()) *GcloudIamClient_GetRoles_Call { +func (_c *GcloudIamClient_GetGrantableRoles_Call) Run(run func(ctx context.Context, resourceType string)) *GcloudIamClient_GetGrantableRoles_Call { _c.Call.Run(func(args mock.Arguments) { - run() + run(args[0].(context.Context), args[1].(string)) }) return _c } -func (_c *GcloudIamClient_GetRoles_Call) Return(_a0 []*gcloudiam.Role, _a1 error) *GcloudIamClient_GetRoles_Call { +func (_c *GcloudIamClient_GetGrantableRoles_Call) Return(_a0 []*iam.Role, _a1 error) *GcloudIamClient_GetGrantableRoles_Call { _c.Call.Return(_a0, _a1) return _c } +func (_c *GcloudIamClient_GetGrantableRoles_Call) RunAndReturn(run func(context.Context, string) ([]*iam.Role, error)) *GcloudIamClient_GetGrantableRoles_Call { + _c.Call.Return(run) + return _c +} + // GrantAccess provides a mock function with given fields: accountType, accountID, role func (_m *GcloudIamClient) GrantAccess(accountType string, accountID string, role string) error { ret := _m.Called(accountType, accountID, role) @@ -89,9 +100,9 @@ type GcloudIamClient_GrantAccess_Call struct { } // GrantAccess is a helper method to define mock.On call -// - accountType string -// - accountID string -// - role string +// - accountType string +// - accountID string +// - role string func (_e *GcloudIamClient_Expecter) GrantAccess(accountType interface{}, accountID interface{}, role interface{}) *GcloudIamClient_GrantAccess_Call { return &GcloudIamClient_GrantAccess_Call{Call: _e.mock.On("GrantAccess", accountType, accountID, role)} } @@ -108,11 +119,66 @@ func (_c *GcloudIamClient_GrantAccess_Call) Return(_a0 error) *GcloudIamClient_G return _c } +func (_c *GcloudIamClient_GrantAccess_Call) RunAndReturn(run func(string, string, string) error) *GcloudIamClient_GrantAccess_Call { + _c.Call.Return(run) + return _c +} + +// GrantServiceAccountAccess provides a mock function with given fields: ctx, sa, accountType, accountID, roles +func (_m *GcloudIamClient) GrantServiceAccountAccess(ctx context.Context, sa string, accountType string, accountID string, roles string) error { + ret := _m.Called(ctx, sa, accountType, accountID, roles) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { + r0 = rf(ctx, sa, accountType, accountID, roles) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GcloudIamClient_GrantServiceAccountAccess_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GrantServiceAccountAccess' +type GcloudIamClient_GrantServiceAccountAccess_Call struct { + *mock.Call +} + +// GrantServiceAccountAccess is a helper method to define mock.On call +// - ctx context.Context +// - sa string +// - accountType string +// - accountID string +// - roles string +func (_e *GcloudIamClient_Expecter) GrantServiceAccountAccess(ctx interface{}, sa interface{}, accountType interface{}, accountID interface{}, roles interface{}) *GcloudIamClient_GrantServiceAccountAccess_Call { + return &GcloudIamClient_GrantServiceAccountAccess_Call{Call: _e.mock.On("GrantServiceAccountAccess", ctx, sa, accountType, accountID, roles)} +} + +func (_c *GcloudIamClient_GrantServiceAccountAccess_Call) Run(run func(ctx context.Context, sa string, accountType string, accountID string, roles string)) *GcloudIamClient_GrantServiceAccountAccess_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string)) + }) + return _c +} + +func (_c *GcloudIamClient_GrantServiceAccountAccess_Call) Return(_a0 error) *GcloudIamClient_GrantServiceAccountAccess_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *GcloudIamClient_GrantServiceAccountAccess_Call) RunAndReturn(run func(context.Context, string, string, string, string) error) *GcloudIamClient_GrantServiceAccountAccess_Call { + _c.Call.Return(run) + return _c +} + // ListAccess provides a mock function with given fields: ctx, resources func (_m *GcloudIamClient) ListAccess(ctx context.Context, resources []*domain.Resource) (domain.MapResourceAccess, error) { ret := _m.Called(ctx, resources) var r0 domain.MapResourceAccess + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []*domain.Resource) (domain.MapResourceAccess, error)); ok { + return rf(ctx, resources) + } if rf, ok := ret.Get(0).(func(context.Context, []*domain.Resource) domain.MapResourceAccess); ok { r0 = rf(ctx, resources) } else { @@ -121,7 +187,6 @@ func (_m *GcloudIamClient) ListAccess(ctx context.Context, resources []*domain.R } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, []*domain.Resource) error); ok { r1 = rf(ctx, resources) } else { @@ -137,8 +202,8 @@ type GcloudIamClient_ListAccess_Call struct { } // ListAccess is a helper method to define mock.On call -// - ctx context.Context -// - resources []*domain.Resource +// - ctx context.Context +// - resources []*domain.Resource func (_e *GcloudIamClient_Expecter) ListAccess(ctx interface{}, resources interface{}) *GcloudIamClient_ListAccess_Call { return &GcloudIamClient_ListAccess_Call{Call: _e.mock.On("ListAccess", ctx, resources)} } @@ -155,6 +220,65 @@ func (_c *GcloudIamClient_ListAccess_Call) Return(_a0 domain.MapResourceAccess, return _c } +func (_c *GcloudIamClient_ListAccess_Call) RunAndReturn(run func(context.Context, []*domain.Resource) (domain.MapResourceAccess, error)) *GcloudIamClient_ListAccess_Call { + _c.Call.Return(run) + return _c +} + +// ListServiceAccounts provides a mock function with given fields: _a0 +func (_m *GcloudIamClient) ListServiceAccounts(_a0 context.Context) ([]*iam.ServiceAccount, error) { + ret := _m.Called(_a0) + + var r0 []*iam.ServiceAccount + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*iam.ServiceAccount, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) []*iam.ServiceAccount); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*iam.ServiceAccount) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GcloudIamClient_ListServiceAccounts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListServiceAccounts' +type GcloudIamClient_ListServiceAccounts_Call struct { + *mock.Call +} + +// ListServiceAccounts is a helper method to define mock.On call +// - _a0 context.Context +func (_e *GcloudIamClient_Expecter) ListServiceAccounts(_a0 interface{}) *GcloudIamClient_ListServiceAccounts_Call { + return &GcloudIamClient_ListServiceAccounts_Call{Call: _e.mock.On("ListServiceAccounts", _a0)} +} + +func (_c *GcloudIamClient_ListServiceAccounts_Call) Run(run func(_a0 context.Context)) *GcloudIamClient_ListServiceAccounts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *GcloudIamClient_ListServiceAccounts_Call) Return(_a0 []*iam.ServiceAccount, _a1 error) *GcloudIamClient_ListServiceAccounts_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GcloudIamClient_ListServiceAccounts_Call) RunAndReturn(run func(context.Context) ([]*iam.ServiceAccount, error)) *GcloudIamClient_ListServiceAccounts_Call { + _c.Call.Return(run) + return _c +} + // RevokeAccess provides a mock function with given fields: accountType, accountID, role func (_m *GcloudIamClient) RevokeAccess(accountType string, accountID string, role string) error { ret := _m.Called(accountType, accountID, role) @@ -175,9 +299,9 @@ type GcloudIamClient_RevokeAccess_Call struct { } // RevokeAccess is a helper method to define mock.On call -// - accountType string -// - accountID string -// - role string +// - accountType string +// - accountID string +// - role string func (_e *GcloudIamClient_Expecter) RevokeAccess(accountType interface{}, accountID interface{}, role interface{}) *GcloudIamClient_RevokeAccess_Call { return &GcloudIamClient_RevokeAccess_Call{Call: _e.mock.On("RevokeAccess", accountType, accountID, role)} } @@ -193,3 +317,69 @@ func (_c *GcloudIamClient_RevokeAccess_Call) Return(_a0 error) *GcloudIamClient_ _c.Call.Return(_a0) return _c } + +func (_c *GcloudIamClient_RevokeAccess_Call) RunAndReturn(run func(string, string, string) error) *GcloudIamClient_RevokeAccess_Call { + _c.Call.Return(run) + return _c +} + +// RevokeServiceAccountAccess provides a mock function with given fields: ctx, sa, accountType, accountID, role +func (_m *GcloudIamClient) RevokeServiceAccountAccess(ctx context.Context, sa string, accountType string, accountID string, role string) error { + ret := _m.Called(ctx, sa, accountType, accountID, role) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { + r0 = rf(ctx, sa, accountType, accountID, role) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GcloudIamClient_RevokeServiceAccountAccess_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RevokeServiceAccountAccess' +type GcloudIamClient_RevokeServiceAccountAccess_Call struct { + *mock.Call +} + +// RevokeServiceAccountAccess is a helper method to define mock.On call +// - ctx context.Context +// - sa string +// - accountType string +// - accountID string +// - role string +func (_e *GcloudIamClient_Expecter) RevokeServiceAccountAccess(ctx interface{}, sa interface{}, accountType interface{}, accountID interface{}, role interface{}) *GcloudIamClient_RevokeServiceAccountAccess_Call { + return &GcloudIamClient_RevokeServiceAccountAccess_Call{Call: _e.mock.On("RevokeServiceAccountAccess", ctx, sa, accountType, accountID, role)} +} + +func (_c *GcloudIamClient_RevokeServiceAccountAccess_Call) Run(run func(ctx context.Context, sa string, accountType string, accountID string, role string)) *GcloudIamClient_RevokeServiceAccountAccess_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string)) + }) + return _c +} + +func (_c *GcloudIamClient_RevokeServiceAccountAccess_Call) Return(_a0 error) *GcloudIamClient_RevokeServiceAccountAccess_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *GcloudIamClient_RevokeServiceAccountAccess_Call) RunAndReturn(run func(context.Context, string, string, string, string) error) *GcloudIamClient_RevokeServiceAccountAccess_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewGcloudIamClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewGcloudIamClient creates a new instance of GcloudIamClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewGcloudIamClient(t mockConstructorTestingTNewGcloudIamClient) *GcloudIamClient { + mock := &GcloudIamClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/plugins/providers/gcloudiam/provider.go b/plugins/providers/gcloudiam/provider.go index 5539844b8..9691686e0 100644 --- a/plugins/providers/gcloudiam/provider.go +++ b/plugins/providers/gcloudiam/provider.go @@ -3,20 +3,23 @@ package gcloudiam import ( "errors" "fmt" - "strings" "github.com/goto/guardian/core/provider" "github.com/goto/guardian/domain" "github.com/mitchellh/mapstructure" "golang.org/x/net/context" + "google.golang.org/api/iam/v1" ) //go:generate mockery --name=GcloudIamClient --exported --with-expecter type GcloudIamClient interface { - GetRoles() ([]*Role, error) + GetGrantableRoles(ctx context.Context, resourceType string) ([]*iam.Role, error) GrantAccess(accountType, accountID, role string) error RevokeAccess(accountType, accountID, role string) error ListAccess(ctx context.Context, resources []*domain.Resource) (domain.MapResourceAccess, error) + ListServiceAccounts(context.Context) ([]*iam.ServiceAccount, error) + GrantServiceAccountAccess(ctx context.Context, sa, accountType, accountID, roles string) error + RevokeServiceAccountAccess(ctx context.Context, sa, accountType, accountID, role string) error } //go:generate mockery --name=encryptor --exported --with-expecter @@ -67,30 +70,55 @@ func (p *Provider) CreateConfig(pc *domain.ProviderConfig) error { } func (p *Provider) GetResources(pc *domain.ProviderConfig) ([]*domain.Resource, error) { - var creds Credentials - if err := mapstructure.Decode(pc.Credentials, &creds); err != nil { - return nil, err - } + resources := []*domain.Resource{} + + for _, rc := range pc.Resources { + switch rc.Type { + case ResourceTypeProject, ResourceTypeOrganization: + var creds Credentials + if err := mapstructure.Decode(pc.Credentials, &creds); err != nil { + return nil, err + } + resources = append(resources, &domain.Resource{ + ProviderType: pc.Type, + ProviderURN: pc.URN, + Type: rc.Type, + URN: creds.ResourceName, + Name: fmt.Sprintf("%s - GCP IAM", creds.ResourceName), + }) + + case ResourceTypeServiceAccount: + client, err := p.getIamClient(pc) + if err != nil { + return nil, fmt.Errorf("initializing iam client: %w", err) + } + + serviceAccounts, err := client.ListServiceAccounts(context.TODO()) + if err != nil { + return nil, fmt.Errorf("listing service accounts: %w", err) + } - var t string - if strings.HasPrefix(creds.ResourceName, "project") { - t = ResourceTypeProject - } else if strings.HasPrefix(creds.ResourceName, "organization") { - t = ResourceTypeOrganization + // TODO: filter + + for _, sa := range serviceAccounts { + resources = append(resources, &domain.Resource{ + ProviderType: pc.Type, + ProviderURN: pc.URN, + Type: rc.Type, + URN: sa.Name, + Name: sa.Email, + }) + } + + default: + return nil, ErrInvalidResourceType + } } - return []*domain.Resource{ - { - ProviderType: pc.Type, - ProviderURN: pc.URN, - Type: t, - URN: creds.ResourceName, - Name: fmt.Sprintf("%s - GCP IAM", creds.ResourceName), - }, - }, nil + return resources, nil } -func (p *Provider) GrantAccess(pc *domain.ProviderConfig, a domain.Grant) error { +func (p *Provider) GrantAccess(pc *domain.ProviderConfig, g domain.Grant) error { // TODO: validate provider config and appeal var creds Credentials @@ -103,23 +131,33 @@ func (p *Provider) GrantAccess(pc *domain.ProviderConfig, a domain.Grant) error return err } - if a.Resource.Type == ResourceTypeProject || a.Resource.Type == ResourceTypeOrganization { - for _, p := range a.Permissions { - permission := fmt.Sprint(p) - if err := client.GrantAccess(a.AccountType, a.AccountID, permission); err != nil { + switch g.Resource.Type { + case ResourceTypeProject, ResourceTypeOrganization: + for _, p := range g.Permissions { + if err := client.GrantAccess(g.AccountType, g.AccountID, p); err != nil { if !errors.Is(err, ErrPermissionAlreadyExists) { return err } } } + return nil + case ResourceTypeServiceAccount: + for _, p := range g.Permissions { + if err := client.GrantServiceAccountAccess(context.TODO(), g.Resource.URN, g.AccountType, g.AccountID, p); err != nil { + if !errors.Is(err, ErrPermissionAlreadyExists) { + return err + } + } + } return nil - } - return ErrInvalidResourceType + default: + return ErrInvalidResourceType + } } -func (p *Provider) RevokeAccess(pc *domain.ProviderConfig, a domain.Grant) error { +func (p *Provider) RevokeAccess(pc *domain.ProviderConfig, g domain.Grant) error { var creds Credentials if err := mapstructure.Decode(pc.Credentials, &creds); err != nil { return err @@ -130,27 +168,33 @@ func (p *Provider) RevokeAccess(pc *domain.ProviderConfig, a domain.Grant) error return err } - if a.Resource.Type == ResourceTypeProject || a.Resource.Type == ResourceTypeOrganization { - for _, p := range a.Permissions { - permission := fmt.Sprint(p) - if err := client.RevokeAccess(a.AccountType, a.AccountID, permission); err != nil { + switch g.Resource.Type { + case ResourceTypeProject, ResourceTypeOrganization: + for _, p := range g.Permissions { + if err := client.RevokeAccess(g.AccountType, g.AccountID, p); err != nil { if !errors.Is(err, ErrPermissionNotFound) { return err } } } + return nil + case ResourceTypeServiceAccount: + for _, p := range g.Permissions { + if err := client.RevokeServiceAccountAccess(context.TODO(), g.Resource.URN, g.AccountType, g.AccountID, p); err != nil { + if !errors.Is(err, ErrPermissionNotFound) { + return err + } + } + } return nil - } - return ErrInvalidResourceType + default: + return ErrInvalidResourceType + } } func (p *Provider) GetRoles(pc *domain.ProviderConfig, resourceType string) ([]*domain.Role, error) { - if resourceType != ResourceTypeProject && resourceType != ResourceTypeOrganization { - return nil, ErrInvalidResourceType - } - return provider.GetRoles(pc, resourceType) } diff --git a/plugins/providers/gcloudiam/provider_test.go b/plugins/providers/gcloudiam/provider_test.go index c37d38300..8d0433a0e 100644 --- a/plugins/providers/gcloudiam/provider_test.go +++ b/plugins/providers/gcloudiam/provider_test.go @@ -10,6 +10,7 @@ import ( "github.com/goto/guardian/plugins/providers/gcloudiam/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "google.golang.org/api/iam/v1" ) func TestCreateConfig(t *testing.T) { @@ -96,9 +97,11 @@ func TestCreateConfig(t *testing.T) { } testcases := []struct { - pc *domain.ProviderConfig + name string + pc *domain.ProviderConfig }{ { + name: "empty resource config", pc: &domain.ProviderConfig{ Credentials: gcloudiam.Credentials{ ServiceAccountKey: base64.StdEncoding.EncodeToString([]byte("service-account-key-json")), @@ -107,6 +110,7 @@ func TestCreateConfig(t *testing.T) { }, }, { + name: "invalid resource type", pc: &domain.ProviderConfig{ Credentials: gcloudiam.Credentials{ ServiceAccountKey: base64.StdEncoding.EncodeToString([]byte("service-account-key-json")), @@ -120,6 +124,39 @@ func TestCreateConfig(t *testing.T) { }, }, { + name: "duplicate resource types", + pc: &domain.ProviderConfig{ + Credentials: gcloudiam.Credentials{ + ServiceAccountKey: base64.StdEncoding.EncodeToString([]byte("service-account-key-json")), + ResourceName: "projects/test-resource-name", + }, + Resources: []*domain.ResourceConfig{ + { + Type: gcloudiam.ResourceTypeProject, + }, + { + Type: gcloudiam.ResourceTypeProject, + }, + }, + }, + }, + { + name: "service_account resource type in organization-level provider", + pc: &domain.ProviderConfig{ + Credentials: gcloudiam.Credentials{ + ServiceAccountKey: base64.StdEncoding.EncodeToString([]byte("service-account-key-json")), + ResourceName: "organizations/my-organization-id", + }, + Resources: []*domain.ResourceConfig{ + { + Type: gcloudiam.ResourceTypeServiceAccount, + }, + }, + URN: providerURN, + }, + }, + { + name: "empty roles", pc: &domain.ProviderConfig{ Credentials: gcloudiam.Credentials{ ServiceAccountKey: base64.StdEncoding.EncodeToString([]byte("service-account-key-json")), @@ -152,16 +189,16 @@ func TestCreateConfig(t *testing.T) { crypto.On("Encrypt", `{"type":"service_account"}`).Return("", expectedError) - gcloudRole1 := &gcloudiam.Role{ - Name: "roles/bigquery.admin", - Title: "BigQuery Admin", - Description: "Administer all BigQuery resources and data", + gCloudRolesList := []*iam.Role{ + { + Name: "roles/bigquery.admin", + Title: "BigQuery Admin", + Description: "Administer all BigQuery resources and data", + }, } - - gCloudRolesList := []*gcloudiam.Role{} - gCloudRolesList = append(gCloudRolesList, gcloudRole1) - - client.On("GetRoles").Return(gCloudRolesList, nil).Once() + client.EXPECT(). + GetGrantableRoles(mock.AnythingOfType("*context.emptyCtx"), gcloudiam.ResourceTypeProject). + Return(gCloudRolesList, nil).Once() pc := &domain.ProviderConfig{ Resources: []*domain.ResourceConfig{ @@ -197,16 +234,16 @@ func TestCreateConfig(t *testing.T) { providerURN: client, } - gcloudRole1 := &gcloudiam.Role{ - Name: "roles/bigquery.admin", - Title: "BigQuery Admin", - Description: "Administer all BigQuery resources and data", + gCloudRolesList := []*iam.Role{ + { + Name: "roles/bigquery.admin", + Title: "BigQuery Admin", + Description: "Administer all BigQuery resources and data", + }, } - - gCloudRolesList := []*gcloudiam.Role{} - gCloudRolesList = append(gCloudRolesList, gcloudRole1) - - client.On("GetRoles").Return(gCloudRolesList, nil).Once() + client.EXPECT(). + GetGrantableRoles(mock.AnythingOfType("*context.emptyCtx"), gcloudiam.ResourceTypeProject). + Return(gCloudRolesList, nil).Once() crypto.On("Encrypt", `{"type":"service_account"}`).Return(`{"type":"service_account"}`, nil) @@ -257,6 +294,9 @@ func TestGetResources(t *testing.T) { Type: domain.ProviderTypeGCloudIAM, URN: "test-project-id", Credentials: "invalid-creds", + Resources: []*domain.ResourceConfig{ + {Type: gcloudiam.ResourceTypeProject}, + }, } actualResources, actualError := p.GetResources(pc) @@ -265,31 +305,50 @@ func TestGetResources(t *testing.T) { assert.Error(t, actualError) }) + providerURN := "test-provider-urn" + crypto := new(mocks.Encryptor) + client := new(mocks.GcloudIamClient) + p := gcloudiam.NewProvider("", crypto) + p.Clients = map[string]gcloudiam.GcloudIamClient{ + providerURN: client, + } + t.Run("should check for valid roles in provider config and return project resource object", func(t *testing.T) { - providerURN := "test-provider-urn" - crypto := new(mocks.Encryptor) - client := new(mocks.GcloudIamClient) - p := gcloudiam.NewProvider("", crypto) - p.Clients = map[string]gcloudiam.GcloudIamClient{ - providerURN: client, + projectRoles := []*iam.Role{ + { + Name: "roles/bigquery.admin", + Title: "BigQuery Admin", + Description: "Administer all BigQuery resources and data", + }, + { + Name: "roles/apigateway.viewer", + Title: "ApiGateway Viewer", + Description: "Read-only access to ApiGateway and related resources", + }, } - - gcloudRole1 := &gcloudiam.Role{ - Name: "roles/bigquery.admin", - Title: "BigQuery Admin", - Description: "Administer all BigQuery resources and data", + saRoles := []*iam.Role{ + { + Name: "roles/workstations.serviceAgent", + Title: "Workstations Service Agent", + Description: "Grants the Workstations Service Account access to manage resources in consumer project.", + }, } - - gcloudRole2 := &gcloudiam.Role{ - Name: "roles/apigateway.viewer", - Title: "ApiGateway Viewer", - Description: "Read-only access to ApiGateway and related resources", + client.EXPECT(). + GetGrantableRoles(mock.AnythingOfType("*context.emptyCtx"), gcloudiam.ResourceTypeProject). + Return(projectRoles, nil).Once() + client.EXPECT(). + GetGrantableRoles(mock.AnythingOfType("*context.emptyCtx"), gcloudiam.ResourceTypeServiceAccount). + Return(saRoles, nil).Once() + + expectedServiceAccounts := []*iam.ServiceAccount{ + { + Name: "sa-name", + Email: "sa-email", + }, } - gCloudRolesList := []*gcloudiam.Role{} - gCloudRolesList = append(gCloudRolesList, gcloudRole1) - gCloudRolesList = append(gCloudRolesList, gcloudRole2) - - client.On("GetRoles").Return(gCloudRolesList, nil).Once() + client.EXPECT(). + ListServiceAccounts(mock.AnythingOfType("*context.emptyCtx")). + Return(expectedServiceAccounts, nil).Once() pc := &domain.ProviderConfig{ Type: domain.ProviderTypeGCloudIAM, @@ -300,7 +359,7 @@ func TestGetResources(t *testing.T) { }, Resources: []*domain.ResourceConfig{ { - Type: "project", + Type: gcloudiam.ResourceTypeProject, Roles: []*domain.Role{ { ID: "role-1", @@ -314,6 +373,15 @@ func TestGetResources(t *testing.T) { }, }, }, + { + Type: gcloudiam.ResourceTypeServiceAccount, + Roles: []*domain.Role{ + { + ID: "role-1", + Permissions: []interface{}{"roles/workstations.serviceAgent"}, + }, + }, + }, }, } @@ -325,6 +393,13 @@ func TestGetResources(t *testing.T) { URN: "project/test-resource-name", Name: "project/test-resource-name - GCP IAM", }, + { + ProviderType: pc.Type, + ProviderURN: pc.URN, + Type: gcloudiam.ResourceTypeServiceAccount, + URN: "sa-name", + Name: "sa-email", + }, } actualResources, actualError := p.GetResources(pc) @@ -333,23 +408,16 @@ func TestGetResources(t *testing.T) { }) t.Run("should return organization resource object", func(t *testing.T) { - providerURN := "test-provider-urn" - crypto := new(mocks.Encryptor) - client := new(mocks.GcloudIamClient) - p := gcloudiam.NewProvider("", crypto) - p.Clients = map[string]gcloudiam.GcloudIamClient{ - providerURN: client, - } - gcloudRole := &gcloudiam.Role{ - Name: "roles/organisation.admin", - Title: "Organisation Admin", - Description: "Administer all Organisation resources and data", + gCloudRolesList := []*iam.Role{ + { + Name: "roles/organisation.admin", + Title: "Organisation Admin", + Description: "Administer all Organisation resources and data", + }, } - - gCloudRolesList := []*gcloudiam.Role{} - gCloudRolesList = append(gCloudRolesList, gcloudRole) - - client.On("GetRoles").Return(gCloudRolesList, nil).Once() + client.EXPECT(). + GetGrantableRoles(mock.AnythingOfType("*context.emptyCtx"), gcloudiam.ResourceTypeOrganization). + Return(gCloudRolesList, nil).Once() pc := &domain.ProviderConfig{ Type: domain.ProviderTypeGCloudIAM, URN: providerURN, @@ -358,7 +426,7 @@ func TestGetResources(t *testing.T) { }, Resources: []*domain.ResourceConfig{ { - Type: "organization", + Type: gcloudiam.ResourceTypeOrganization, Roles: []*domain.Role{ { ID: "role-1", @@ -385,6 +453,65 @@ func TestGetResources(t *testing.T) { assert.Equal(t, expectedResources, actualResources) assert.Nil(t, actualError) }) + + t.Run("should return error if resource type in invalid", func(t *testing.T) { + pc := &domain.ProviderConfig{ + Type: domain.ProviderTypeGCloudIAM, + URN: providerURN, + Credentials: map[string]interface{}{ + "resource_name": "project/test-resource-name", + }, + Resources: []*domain.ResourceConfig{ + {Type: "invalid-resource-type"}, + }, + } + _, err := p.GetResources(pc) + + assert.ErrorIs(t, err, gcloudiam.ErrInvalidResourceType) + }) + + t.Run("get service accounts resources", func(t *testing.T) { + t.Run("should return error if client initialization failed", func(t *testing.T) { + pc := &domain.ProviderConfig{ + Type: domain.ProviderTypeGCloudIAM, + URN: providerURN, + Credentials: map[string]interface{}{ + "resource_name": make(chan int), + }, + Resources: []*domain.ResourceConfig{ + { + Type: gcloudiam.ResourceTypeServiceAccount, + }, + }, + } + + _, actualError := p.GetResources(pc) + + assert.Error(t, actualError) + }) + + t.Run("should return error if client returns an error", func(t *testing.T) { + expectedError := errors.New("client error") + client.On("ListServiceAccounts", mock.AnythingOfType("*context.emptyCtx")).Return(nil, expectedError).Once() + + pc := &domain.ProviderConfig{ + Type: domain.ProviderTypeGCloudIAM, + URN: providerURN, + Credentials: map[string]interface{}{ + "resource_name": "project/test-resource-name", + }, + Resources: []*domain.ResourceConfig{ + { + Type: gcloudiam.ResourceTypeServiceAccount, + }, + }, + } + + _, actualError := p.GetResources(pc) + + assert.ErrorIs(t, actualError, expectedError) + }) + }) } func TestGrantAccess(t *testing.T) { @@ -443,15 +570,107 @@ func TestGrantAccess(t *testing.T) { }) t.Run("should return error if there is an error in granting the access", func(t *testing.T) { + expectedError := errors.New("client error in granting access") + testCases := []struct { + name string + resourceType string + expectedError error + setExpectationFunc func(*mocks.GcloudIamClient) + }{ + { + name: "for project", + resourceType: gcloudiam.ResourceTypeProject, + expectedError: expectedError, + setExpectationFunc: func(c *mocks.GcloudIamClient) { + c.EXPECT(). + GrantAccess(mock.Anything, mock.Anything, mock.Anything). + Return(expectedError).Once() + }, + }, + { + name: "for organization", + resourceType: gcloudiam.ResourceTypeOrganization, + expectedError: expectedError, + setExpectationFunc: func(c *mocks.GcloudIamClient) { + c.EXPECT(). + GrantAccess(mock.Anything, mock.Anything, mock.Anything). + Return(expectedError).Once() + }, + }, + { + name: "for service account", + resourceType: gcloudiam.ResourceTypeServiceAccount, + expectedError: expectedError, + setExpectationFunc: func(c *mocks.GcloudIamClient) { + c.EXPECT(). + GrantServiceAccountAccess(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(expectedError).Once() + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + providerURN := "test-provider-urn" + crypto := new(mocks.Encryptor) + client := new(mocks.GcloudIamClient) + p := gcloudiam.NewProvider("", crypto) + p.Clients = map[string]gcloudiam.GcloudIamClient{ + providerURN: client, + } + + tc.setExpectationFunc(client) + + pc := &domain.ProviderConfig{ + Resources: []*domain.ResourceConfig{ + { + Type: tc.resourceType, + Roles: []*domain.Role{ + { + ID: "role-1", + Name: "role-name-1", + Permissions: []interface{}{"permission-1"}, + }, + { + ID: "role-2", + Name: "role-name-2", + Permissions: []interface{}{"permission-2"}, + }, + }, + }, + }, + URN: providerURN, + } + a := domain.Grant{ + Resource: &domain.Resource{ + Type: tc.resourceType, + URN: "999", + Name: "test-role", + }, + Role: "role-1", + Permissions: []string{"permission-1"}, + } + + actualError := p.GrantAccess(pc, a) + + assert.EqualError(t, actualError, tc.expectedError.Error()) + }) + } + }) + + t.Run("should return nil error if granting access is successful", func(t *testing.T) { providerURN := "test-provider-urn" - expectedError := errors.New("client error") crypto := new(mocks.Encryptor) client := new(mocks.GcloudIamClient) + expectedRole := "role-1" + expectedAccountType := "user" + expectedAccountID := "test@email.com" + expectedPermission := "roles/bigquery.admin" p := gcloudiam.NewProvider("", crypto) p.Clients = map[string]gcloudiam.GcloudIamClient{ providerURN: client, } - client.On("GrantAccess", mock.Anything, mock.Anything, mock.Anything).Return(expectedError).Once() + client.On("GrantAccess", expectedAccountType, expectedAccountID, expectedPermission).Return(nil).Once() pc := &domain.ProviderConfig{ Resources: []*domain.ResourceConfig{ @@ -473,71 +692,64 @@ func TestGrantAccess(t *testing.T) { }, URN: providerURN, } - a := domain.Grant{ + g := domain.Grant{ Resource: &domain.Resource{ Type: gcloudiam.ResourceTypeProject, - URN: "999", - Name: "test-role", + URN: "test-role", }, - Role: "role-1", + Role: expectedRole, + AccountType: expectedAccountType, + AccountID: expectedAccountID, + ResourceID: "999", + ID: "999", Permissions: []string{"roles/bigquery.admin"}, } - actualError := p.GrantAccess(pc, a) + actualError := p.GrantAccess(pc, g) - assert.EqualError(t, actualError, expectedError.Error()) + assert.Nil(t, actualError) }) - t.Run("should return nil error if granting access is successful", func(t *testing.T) { + t.Run("successful grant access to a service account", func(t *testing.T) { providerURN := "test-provider-urn" crypto := new(mocks.Encryptor) client := new(mocks.GcloudIamClient) - expectedRole := "role-1" - expectedAccountType := "user" - expectedAccountID := "test@email.com" - expectedPermission := "roles/bigquery.admin" p := gcloudiam.NewProvider("", crypto) p.Clients = map[string]gcloudiam.GcloudIamClient{ providerURN: client, } - client.On("GrantAccess", expectedAccountType, expectedAccountID, expectedPermission).Return(nil).Once() pc := &domain.ProviderConfig{ + URN: providerURN, Resources: []*domain.ResourceConfig{ { - Type: gcloudiam.ResourceTypeProject, + Type: gcloudiam.ResourceTypeServiceAccount, Roles: []*domain.Role{ { - ID: "role-1", - Name: "BigQuery", - Permissions: []interface{}{"roles/bigquery.admin"}, - }, - { - ID: "role-2", - Name: "Api gateway", - Permissions: []interface{}{"roles/apigateway.viewer"}, + ID: "test-role", + Permissions: []interface{}{"test-permission"}, }, }, }, }, - URN: providerURN, } - a := domain.Grant{ + g := domain.Grant{ Resource: &domain.Resource{ - Type: gcloudiam.ResourceTypeProject, - URN: "test-role", + Type: gcloudiam.ResourceTypeServiceAccount, + URN: "sa-urn", }, - Role: expectedRole, - AccountType: expectedAccountType, - AccountID: expectedAccountID, - ResourceID: "999", - ID: "999", - Permissions: []string{"roles/bigquery.admin"}, + Role: "test-role", + AccountType: "test-account-type", + AccountID: "test-account-id", + Permissions: []string{"test-permission"}, } - actualError := p.GrantAccess(pc, a) + client.EXPECT(). + GrantServiceAccountAccess(mock.AnythingOfType("*context.emptyCtx"), g.Resource.URN, g.AccountType, g.AccountID, g.Permissions[0]). + Return(nil).Once() - assert.Nil(t, actualError) + err := p.GrantAccess(pc, g) + assert.NoError(t, err) }) } @@ -573,15 +785,107 @@ func TestRevokeAccess(t *testing.T) { }) t.Run("should return error if there is an error in revoking the access", func(t *testing.T) { + expectedError := errors.New("client error in revoking access") + testCases := []struct { + name string + resourceType string + expectedError error + setExpectationFunc func(*mocks.GcloudIamClient) + }{ + { + name: "for project", + resourceType: gcloudiam.ResourceTypeProject, + expectedError: expectedError, + setExpectationFunc: func(c *mocks.GcloudIamClient) { + c.EXPECT(). + RevokeAccess(mock.Anything, mock.Anything, mock.Anything). + Return(expectedError).Once() + }, + }, + { + name: "for organization", + resourceType: gcloudiam.ResourceTypeOrganization, + expectedError: expectedError, + setExpectationFunc: func(c *mocks.GcloudIamClient) { + c.EXPECT(). + RevokeAccess(mock.Anything, mock.Anything, mock.Anything). + Return(expectedError).Once() + }, + }, + { + name: "for service account", + resourceType: gcloudiam.ResourceTypeServiceAccount, + expectedError: expectedError, + setExpectationFunc: func(c *mocks.GcloudIamClient) { + c.EXPECT(). + RevokeServiceAccountAccess(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(expectedError).Once() + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + providerURN := "test-provider-urn" + crypto := new(mocks.Encryptor) + client := new(mocks.GcloudIamClient) + p := gcloudiam.NewProvider("", crypto) + p.Clients = map[string]gcloudiam.GcloudIamClient{ + providerURN: client, + } + + tc.setExpectationFunc(client) + + pc := &domain.ProviderConfig{ + Resources: []*domain.ResourceConfig{ + { + Type: tc.resourceType, + Roles: []*domain.Role{ + { + ID: "role-1", + Name: "role-name-1", + Permissions: []interface{}{"permission-1"}, + }, + { + ID: "role-2", + Name: "role-name-2", + Permissions: []interface{}{"permission-2"}, + }, + }, + }, + }, + URN: providerURN, + } + a := domain.Grant{ + Resource: &domain.Resource{ + Type: tc.resourceType, + URN: "999", + Name: "test-role", + }, + Role: "role-1", + Permissions: []string{"permission-1"}, + } + + actualError := p.RevokeAccess(pc, a) + + assert.EqualError(t, actualError, tc.expectedError.Error()) + }) + } + }) + + t.Run("should return nil error if revoking access is successful", func(t *testing.T) { providerURN := "test-provider-urn" - expectedError := errors.New("client error") crypto := new(mocks.Encryptor) client := new(mocks.GcloudIamClient) + expectedRole := "role-1" + expectedPermission := "roles/bigquery.admin" + expectedAccountType := "user" + expectedAccountID := "test@email.com" p := gcloudiam.NewProvider("", crypto) p.Clients = map[string]gcloudiam.GcloudIamClient{ providerURN: client, } - client.On("RevokeAccess", mock.Anything, mock.Anything, mock.Anything).Return(expectedError).Once() + client.On("RevokeAccess", expectedAccountType, expectedAccountID, expectedPermission).Return(nil).Once() pc := &domain.ProviderConfig{ Resources: []*domain.ResourceConfig{ @@ -606,67 +910,60 @@ func TestRevokeAccess(t *testing.T) { a := domain.Grant{ Resource: &domain.Resource{ Type: gcloudiam.ResourceTypeProject, - URN: "999", - Name: "test-role", + URN: "test-role", }, - Role: "role-1", - Permissions: []string{"roles/bigquery.admin"}, + Role: expectedRole, + AccountType: expectedAccountType, + AccountID: expectedAccountID, + ResourceID: "999", + ID: "999", } actualError := p.RevokeAccess(pc, a) - assert.EqualError(t, actualError, expectedError.Error()) + assert.Nil(t, actualError) }) - t.Run("should return nil error if revoking access is successful", func(t *testing.T) { + t.Run("successful revoke access to a service account", func(t *testing.T) { providerURN := "test-provider-urn" crypto := new(mocks.Encryptor) client := new(mocks.GcloudIamClient) - expectedRole := "role-1" - expectedPermission := "roles/bigquery.admin" - expectedAccountType := "user" - expectedAccountID := "test@email.com" p := gcloudiam.NewProvider("", crypto) p.Clients = map[string]gcloudiam.GcloudIamClient{ providerURN: client, } - client.On("RevokeAccess", expectedAccountType, expectedAccountID, expectedPermission).Return(nil).Once() pc := &domain.ProviderConfig{ + URN: providerURN, Resources: []*domain.ResourceConfig{ { - Type: gcloudiam.ResourceTypeProject, + Type: gcloudiam.ResourceTypeServiceAccount, Roles: []*domain.Role{ { - ID: "role-1", - Name: "BigQuery", - Permissions: []interface{}{"roles/bigquery.admin"}, - }, - { - ID: "role-2", - Name: "Api gateway", - Permissions: []interface{}{"roles/apigateway.viewer"}, + ID: "test-role", + Permissions: []interface{}{"test-permission"}, }, }, }, }, - URN: providerURN, } - a := domain.Grant{ + g := domain.Grant{ Resource: &domain.Resource{ - Type: gcloudiam.ResourceTypeProject, - URN: "test-role", + Type: gcloudiam.ResourceTypeServiceAccount, + URN: "sa-urn", }, - Role: expectedRole, - AccountType: expectedAccountType, - AccountID: expectedAccountID, - ResourceID: "999", - ID: "999", + Role: "test-role", + AccountType: "test-account-type", + AccountID: "test-account-id", + Permissions: []string{"test-permission"}, } - actualError := p.RevokeAccess(pc, a) + client.EXPECT(). + RevokeServiceAccountAccess(mock.AnythingOfType("*context.emptyCtx"), g.Resource.URN, g.AccountType, g.AccountID, g.Permissions[0]). + Return(nil).Once() - assert.Nil(t, actualError) + err := p.RevokeAccess(pc, g) + assert.NoError(t, err) }) } diff --git a/plugins/providers/gcloudiam/resource.go b/plugins/providers/gcloudiam/resource.go index ed3efc8cd..76f64b4c5 100644 --- a/plugins/providers/gcloudiam/resource.go +++ b/plugins/providers/gcloudiam/resource.go @@ -1,8 +1,9 @@ package gcloudiam const ( - ResourceTypeProject = "project" - ResourceTypeOrganization = "organization" + ResourceTypeProject = "project" + ResourceTypeOrganization = "organization" + ResourceTypeServiceAccount = "service_account" ) type Role struct {