From 819bc4156e2d95427b0e76d56f9e6f6d4c490eb6 Mon Sep 17 00:00:00 2001 From: Fiachra Corcoran Date: Tue, 27 Feb 2024 10:54:46 +0000 Subject: [PATCH] Add test coverage to token rec (#511) Refactor existing test to use mockery helper functions Add controller-runtime mock --- controllers/pkg/.mockery.yaml | 9 +- controllers/pkg/giteaclient/giteaclient.go | 10 + .../pkg/giteaclient/mock_GiteaClient.go | 127 ++- .../pkg/mocks/external/client/mock_Client.go | 731 ++++++++++++++++++ .../pkg/reconcilers/token/reconciler.go | 17 +- .../pkg/reconcilers/token/reconciler_test.go | 206 +++-- 6 files changed, 1043 insertions(+), 57 deletions(-) create mode 100644 controllers/pkg/mocks/external/client/mock_Client.go diff --git a/controllers/pkg/.mockery.yaml b/controllers/pkg/.mockery.yaml index 7baec8e4..80b2e0f2 100644 --- a/controllers/pkg/.mockery.yaml +++ b/controllers/pkg/.mockery.yaml @@ -1,6 +1,13 @@ +with-expecter: true packages: github.com/nephio-project/nephio/controllers/pkg/giteaclient: interfaces: GiteaClient: config: - dir: "{{.InterfaceDir}}" \ No newline at end of file + dir: "{{.InterfaceDir}}" + sigs.k8s.io/controller-runtime/pkg/client: + interfaces: + Client: + config: + dir: "mocks/external/{{ .InterfaceName | lower }}" + outpkg: "mocks" \ No newline at end of file diff --git a/controllers/pkg/giteaclient/giteaclient.go b/controllers/pkg/giteaclient/giteaclient.go index f2b9c63e..f925bfa0 100644 --- a/controllers/pkg/giteaclient/giteaclient.go +++ b/controllers/pkg/giteaclient/giteaclient.go @@ -41,6 +41,8 @@ type GiteaClient interface { CreateRepo(createRepoOption gitea.CreateRepoOption) (*gitea.Repository, *gitea.Response, error) EditRepo(userName string, repoCRName string, editRepoOption gitea.EditRepoOption) (*gitea.Repository, *gitea.Response, error) DeleteAccessToken(value interface{}) (*gitea.Response, error) + ListAccessTokens(opts gitea.ListAccessTokensOptions) ([]*gitea.AccessToken, *gitea.Response, error) + CreateAccessToken(opt gitea.CreateAccessTokenOption) (*gitea.AccessToken, *gitea.Response, error) } var lock = &sync.Mutex{} @@ -171,3 +173,11 @@ func (r *gc) EditRepo(userName string, repoCRName string, editRepoOption gitea.E func (r *gc) DeleteAccessToken(value interface{}) (*gitea.Response, error) { return r.giteaClient.DeleteAccessToken(value) } + +func (r *gc) ListAccessTokens(opts gitea.ListAccessTokensOptions) ([]*gitea.AccessToken, *gitea.Response, error) { + return r.giteaClient.ListAccessTokens(opts) +} + +func (r *gc) CreateAccessToken(opt gitea.CreateAccessTokenOption) (*gitea.AccessToken, *gitea.Response, error) { + return r.giteaClient.CreateAccessToken(opt) +} diff --git a/controllers/pkg/giteaclient/mock_GiteaClient.go b/controllers/pkg/giteaclient/mock_GiteaClient.go index c1ad79d6..4b9b18bd 100644 --- a/controllers/pkg/giteaclient/mock_GiteaClient.go +++ b/controllers/pkg/giteaclient/mock_GiteaClient.go @@ -23,6 +23,69 @@ func (_m *MockGiteaClient) EXPECT() *MockGiteaClient_Expecter { return &MockGiteaClient_Expecter{mock: &_m.Mock} } +// CreateAccessToken provides a mock function with given fields: opt +func (_m *MockGiteaClient) CreateAccessToken(opt gitea.CreateAccessTokenOption) (*gitea.AccessToken, *gitea.Response, error) { + ret := _m.Called(opt) + + var r0 *gitea.AccessToken + var r1 *gitea.Response + var r2 error + if rf, ok := ret.Get(0).(func(gitea.CreateAccessTokenOption) (*gitea.AccessToken, *gitea.Response, error)); ok { + return rf(opt) + } + if rf, ok := ret.Get(0).(func(gitea.CreateAccessTokenOption) *gitea.AccessToken); ok { + r0 = rf(opt) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.AccessToken) + } + } + + if rf, ok := ret.Get(1).(func(gitea.CreateAccessTokenOption) *gitea.Response); ok { + r1 = rf(opt) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*gitea.Response) + } + } + + if rf, ok := ret.Get(2).(func(gitea.CreateAccessTokenOption) error); ok { + r2 = rf(opt) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockGiteaClient_CreateAccessToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateAccessToken' +type MockGiteaClient_CreateAccessToken_Call struct { + *mock.Call +} + +// CreateAccessToken is a helper method to define mock.On call +// - opt gitea.CreateAccessTokenOption +func (_e *MockGiteaClient_Expecter) CreateAccessToken(opt interface{}) *MockGiteaClient_CreateAccessToken_Call { + return &MockGiteaClient_CreateAccessToken_Call{Call: _e.mock.On("CreateAccessToken", opt)} +} + +func (_c *MockGiteaClient_CreateAccessToken_Call) Run(run func(opt gitea.CreateAccessTokenOption)) *MockGiteaClient_CreateAccessToken_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(gitea.CreateAccessTokenOption)) + }) + return _c +} + +func (_c *MockGiteaClient_CreateAccessToken_Call) Return(_a0 *gitea.AccessToken, _a1 *gitea.Response, _a2 error) *MockGiteaClient_CreateAccessToken_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockGiteaClient_CreateAccessToken_Call) RunAndReturn(run func(gitea.CreateAccessTokenOption) (*gitea.AccessToken, *gitea.Response, error)) *MockGiteaClient_CreateAccessToken_Call { + _c.Call.Return(run) + return _c +} + // CreateRepo provides a mock function with given fields: createRepoOption func (_m *MockGiteaClient) CreateRepo(createRepoOption gitea.CreateRepoOption) (*gitea.Repository, *gitea.Response, error) { ret := _m.Called(createRepoOption) @@ -86,7 +149,6 @@ func (_c *MockGiteaClient_CreateRepo_Call) RunAndReturn(run func(gitea.CreateRep return _c } - // DeleteAccessToken provides a mock function with given fields: value func (_m *MockGiteaClient) DeleteAccessToken(value interface{}) (*gitea.Response, error) { ret := _m.Called(value) @@ -471,6 +533,69 @@ func (_c *MockGiteaClient_IsInitialized_Call) RunAndReturn(run func() bool) *Moc return _c } +// ListAccessTokens provides a mock function with given fields: opts +func (_m *MockGiteaClient) ListAccessTokens(opts gitea.ListAccessTokensOptions) ([]*gitea.AccessToken, *gitea.Response, error) { + ret := _m.Called(opts) + + var r0 []*gitea.AccessToken + var r1 *gitea.Response + var r2 error + if rf, ok := ret.Get(0).(func(gitea.ListAccessTokensOptions) ([]*gitea.AccessToken, *gitea.Response, error)); ok { + return rf(opts) + } + if rf, ok := ret.Get(0).(func(gitea.ListAccessTokensOptions) []*gitea.AccessToken); ok { + r0 = rf(opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*gitea.AccessToken) + } + } + + if rf, ok := ret.Get(1).(func(gitea.ListAccessTokensOptions) *gitea.Response); ok { + r1 = rf(opts) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*gitea.Response) + } + } + + if rf, ok := ret.Get(2).(func(gitea.ListAccessTokensOptions) error); ok { + r2 = rf(opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockGiteaClient_ListAccessTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListAccessTokens' +type MockGiteaClient_ListAccessTokens_Call struct { + *mock.Call +} + +// ListAccessTokens is a helper method to define mock.On call +// - opts gitea.ListAccessTokensOptions +func (_e *MockGiteaClient_Expecter) ListAccessTokens(opts interface{}) *MockGiteaClient_ListAccessTokens_Call { + return &MockGiteaClient_ListAccessTokens_Call{Call: _e.mock.On("ListAccessTokens", opts)} +} + +func (_c *MockGiteaClient_ListAccessTokens_Call) Run(run func(opts gitea.ListAccessTokensOptions)) *MockGiteaClient_ListAccessTokens_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(gitea.ListAccessTokensOptions)) + }) + return _c +} + +func (_c *MockGiteaClient_ListAccessTokens_Call) Return(_a0 []*gitea.AccessToken, _a1 *gitea.Response, _a2 error) *MockGiteaClient_ListAccessTokens_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockGiteaClient_ListAccessTokens_Call) RunAndReturn(run func(gitea.ListAccessTokensOptions) ([]*gitea.AccessToken, *gitea.Response, error)) *MockGiteaClient_ListAccessTokens_Call { + _c.Call.Return(run) + return _c +} + // Start provides a mock function with given fields: ctx func (_m *MockGiteaClient) Start(ctx context.Context) { _m.Called(ctx) diff --git a/controllers/pkg/mocks/external/client/mock_Client.go b/controllers/pkg/mocks/external/client/mock_Client.go new file mode 100644 index 00000000..0500bc2d --- /dev/null +++ b/controllers/pkg/mocks/external/client/mock_Client.go @@ -0,0 +1,731 @@ +// Code generated by mockery v2.37.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + client "sigs.k8s.io/controller-runtime/pkg/client" + + meta "k8s.io/apimachinery/pkg/api/meta" + + mock "github.com/stretchr/testify/mock" + + runtime "k8s.io/apimachinery/pkg/runtime" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + + types "k8s.io/apimachinery/pkg/types" +) + +// MockClient is an autogenerated mock type for the Client type +type MockClient struct { + mock.Mock +} + +type MockClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockClient) EXPECT() *MockClient_Expecter { + return &MockClient_Expecter{mock: &_m.Mock} +} + +// Create provides a mock function with given fields: ctx, obj, opts +func (_m *MockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.CreateOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' +type MockClient_Create_Call struct { + *mock.Call +} + +// Create is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.CreateOption +func (_e *MockClient_Expecter) Create(ctx interface{}, obj interface{}, opts ...interface{}) *MockClient_Create_Call { + return &MockClient_Create_Call{Call: _e.mock.On("Create", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *MockClient_Create_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.CreateOption)) *MockClient_Create_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.CreateOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.CreateOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_Create_Call) Return(_a0 error) *MockClient_Create_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Create_Call) RunAndReturn(run func(context.Context, client.Object, ...client.CreateOption) error) *MockClient_Create_Call { + _c.Call.Return(run) + return _c +} + +// Delete provides a mock function with given fields: ctx, obj, opts +func (_m *MockClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' +type MockClient_Delete_Call struct { + *mock.Call +} + +// Delete is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.DeleteOption +func (_e *MockClient_Expecter) Delete(ctx interface{}, obj interface{}, opts ...interface{}) *MockClient_Delete_Call { + return &MockClient_Delete_Call{Call: _e.mock.On("Delete", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *MockClient_Delete_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.DeleteOption)) *MockClient_Delete_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.DeleteOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.DeleteOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_Delete_Call) Return(_a0 error) *MockClient_Delete_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Delete_Call) RunAndReturn(run func(context.Context, client.Object, ...client.DeleteOption) error) *MockClient_Delete_Call { + _c.Call.Return(run) + return _c +} + +// DeleteAllOf provides a mock function with given fields: ctx, obj, opts +func (_m *MockClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteAllOfOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_DeleteAllOf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteAllOf' +type MockClient_DeleteAllOf_Call struct { + *mock.Call +} + +// DeleteAllOf is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.DeleteAllOfOption +func (_e *MockClient_Expecter) DeleteAllOf(ctx interface{}, obj interface{}, opts ...interface{}) *MockClient_DeleteAllOf_Call { + return &MockClient_DeleteAllOf_Call{Call: _e.mock.On("DeleteAllOf", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *MockClient_DeleteAllOf_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption)) *MockClient_DeleteAllOf_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.DeleteAllOfOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.DeleteAllOfOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_DeleteAllOf_Call) Return(_a0 error) *MockClient_DeleteAllOf_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_DeleteAllOf_Call) RunAndReturn(run func(context.Context, client.Object, ...client.DeleteAllOfOption) error) *MockClient_DeleteAllOf_Call { + _c.Call.Return(run) + return _c +} + +// Get provides a mock function with given fields: ctx, key, obj, opts +func (_m *MockClient) Get(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, key, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error); ok { + r0 = rf(ctx, key, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type MockClient_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - ctx context.Context +// - key types.NamespacedName +// - obj client.Object +// - opts ...client.GetOption +func (_e *MockClient_Expecter) Get(ctx interface{}, key interface{}, obj interface{}, opts ...interface{}) *MockClient_Get_Call { + return &MockClient_Get_Call{Call: _e.mock.On("Get", + append([]interface{}{ctx, key, obj}, opts...)...)} +} + +func (_c *MockClient_Get_Call) Run(run func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption)) *MockClient_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.GetOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(client.GetOption) + } + } + run(args[0].(context.Context), args[1].(types.NamespacedName), args[2].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_Get_Call) Return(_a0 error) *MockClient_Get_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Get_Call) RunAndReturn(run func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error) *MockClient_Get_Call { + _c.Call.Return(run) + return _c +} + +// GroupVersionKindFor provides a mock function with given fields: obj +func (_m *MockClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { + ret := _m.Called(obj) + + var r0 schema.GroupVersionKind + var r1 error + if rf, ok := ret.Get(0).(func(runtime.Object) (schema.GroupVersionKind, error)); ok { + return rf(obj) + } + if rf, ok := ret.Get(0).(func(runtime.Object) schema.GroupVersionKind); ok { + r0 = rf(obj) + } else { + r0 = ret.Get(0).(schema.GroupVersionKind) + } + + if rf, ok := ret.Get(1).(func(runtime.Object) error); ok { + r1 = rf(obj) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_GroupVersionKindFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GroupVersionKindFor' +type MockClient_GroupVersionKindFor_Call struct { + *mock.Call +} + +// GroupVersionKindFor is a helper method to define mock.On call +// - obj runtime.Object +func (_e *MockClient_Expecter) GroupVersionKindFor(obj interface{}) *MockClient_GroupVersionKindFor_Call { + return &MockClient_GroupVersionKindFor_Call{Call: _e.mock.On("GroupVersionKindFor", obj)} +} + +func (_c *MockClient_GroupVersionKindFor_Call) Run(run func(obj runtime.Object)) *MockClient_GroupVersionKindFor_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(runtime.Object)) + }) + return _c +} + +func (_c *MockClient_GroupVersionKindFor_Call) Return(_a0 schema.GroupVersionKind, _a1 error) *MockClient_GroupVersionKindFor_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_GroupVersionKindFor_Call) RunAndReturn(run func(runtime.Object) (schema.GroupVersionKind, error)) *MockClient_GroupVersionKindFor_Call { + _c.Call.Return(run) + return _c +} + +// IsObjectNamespaced provides a mock function with given fields: obj +func (_m *MockClient) IsObjectNamespaced(obj runtime.Object) (bool, error) { + ret := _m.Called(obj) + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(runtime.Object) (bool, error)); ok { + return rf(obj) + } + if rf, ok := ret.Get(0).(func(runtime.Object) bool); ok { + r0 = rf(obj) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(runtime.Object) error); ok { + r1 = rf(obj) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_IsObjectNamespaced_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsObjectNamespaced' +type MockClient_IsObjectNamespaced_Call struct { + *mock.Call +} + +// IsObjectNamespaced is a helper method to define mock.On call +// - obj runtime.Object +func (_e *MockClient_Expecter) IsObjectNamespaced(obj interface{}) *MockClient_IsObjectNamespaced_Call { + return &MockClient_IsObjectNamespaced_Call{Call: _e.mock.On("IsObjectNamespaced", obj)} +} + +func (_c *MockClient_IsObjectNamespaced_Call) Run(run func(obj runtime.Object)) *MockClient_IsObjectNamespaced_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(runtime.Object)) + }) + return _c +} + +func (_c *MockClient_IsObjectNamespaced_Call) Return(_a0 bool, _a1 error) *MockClient_IsObjectNamespaced_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_IsObjectNamespaced_Call) RunAndReturn(run func(runtime.Object) (bool, error)) *MockClient_IsObjectNamespaced_Call { + _c.Call.Return(run) + return _c +} + +// List provides a mock function with given fields: ctx, list, opts +func (_m *MockClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, list) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.ObjectList, ...client.ListOption) error); ok { + r0 = rf(ctx, list, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' +type MockClient_List_Call struct { + *mock.Call +} + +// List is a helper method to define mock.On call +// - ctx context.Context +// - list client.ObjectList +// - opts ...client.ListOption +func (_e *MockClient_Expecter) List(ctx interface{}, list interface{}, opts ...interface{}) *MockClient_List_Call { + return &MockClient_List_Call{Call: _e.mock.On("List", + append([]interface{}{ctx, list}, opts...)...)} +} + +func (_c *MockClient_List_Call) Run(run func(ctx context.Context, list client.ObjectList, opts ...client.ListOption)) *MockClient_List_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.ListOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.ListOption) + } + } + run(args[0].(context.Context), args[1].(client.ObjectList), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_List_Call) Return(_a0 error) *MockClient_List_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_List_Call) RunAndReturn(run func(context.Context, client.ObjectList, ...client.ListOption) error) *MockClient_List_Call { + _c.Call.Return(run) + return _c +} + +// Patch provides a mock function with given fields: ctx, obj, patch, opts +func (_m *MockClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj, patch) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, client.Patch, ...client.PatchOption) error); ok { + r0 = rf(ctx, obj, patch, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_Patch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Patch' +type MockClient_Patch_Call struct { + *mock.Call +} + +// Patch is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - patch client.Patch +// - opts ...client.PatchOption +func (_e *MockClient_Expecter) Patch(ctx interface{}, obj interface{}, patch interface{}, opts ...interface{}) *MockClient_Patch_Call { + return &MockClient_Patch_Call{Call: _e.mock.On("Patch", + append([]interface{}{ctx, obj, patch}, opts...)...)} +} + +func (_c *MockClient_Patch_Call) Run(run func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption)) *MockClient_Patch_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.PatchOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(client.PatchOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), args[2].(client.Patch), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_Patch_Call) Return(_a0 error) *MockClient_Patch_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Patch_Call) RunAndReturn(run func(context.Context, client.Object, client.Patch, ...client.PatchOption) error) *MockClient_Patch_Call { + _c.Call.Return(run) + return _c +} + +// RESTMapper provides a mock function with given fields: +func (_m *MockClient) RESTMapper() meta.RESTMapper { + ret := _m.Called() + + var r0 meta.RESTMapper + if rf, ok := ret.Get(0).(func() meta.RESTMapper); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(meta.RESTMapper) + } + } + + return r0 +} + +// MockClient_RESTMapper_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RESTMapper' +type MockClient_RESTMapper_Call struct { + *mock.Call +} + +// RESTMapper is a helper method to define mock.On call +func (_e *MockClient_Expecter) RESTMapper() *MockClient_RESTMapper_Call { + return &MockClient_RESTMapper_Call{Call: _e.mock.On("RESTMapper")} +} + +func (_c *MockClient_RESTMapper_Call) Run(run func()) *MockClient_RESTMapper_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockClient_RESTMapper_Call) Return(_a0 meta.RESTMapper) *MockClient_RESTMapper_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_RESTMapper_Call) RunAndReturn(run func() meta.RESTMapper) *MockClient_RESTMapper_Call { + _c.Call.Return(run) + return _c +} + +// Scheme provides a mock function with given fields: +func (_m *MockClient) Scheme() *runtime.Scheme { + ret := _m.Called() + + var r0 *runtime.Scheme + if rf, ok := ret.Get(0).(func() *runtime.Scheme); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*runtime.Scheme) + } + } + + return r0 +} + +// MockClient_Scheme_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Scheme' +type MockClient_Scheme_Call struct { + *mock.Call +} + +// Scheme is a helper method to define mock.On call +func (_e *MockClient_Expecter) Scheme() *MockClient_Scheme_Call { + return &MockClient_Scheme_Call{Call: _e.mock.On("Scheme")} +} + +func (_c *MockClient_Scheme_Call) Run(run func()) *MockClient_Scheme_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockClient_Scheme_Call) Return(_a0 *runtime.Scheme) *MockClient_Scheme_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Scheme_Call) RunAndReturn(run func() *runtime.Scheme) *MockClient_Scheme_Call { + _c.Call.Return(run) + return _c +} + +// Status provides a mock function with given fields: +func (_m *MockClient) Status() client.SubResourceWriter { + ret := _m.Called() + + var r0 client.SubResourceWriter + if rf, ok := ret.Get(0).(func() client.SubResourceWriter); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.SubResourceWriter) + } + } + + return r0 +} + +// MockClient_Status_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Status' +type MockClient_Status_Call struct { + *mock.Call +} + +// Status is a helper method to define mock.On call +func (_e *MockClient_Expecter) Status() *MockClient_Status_Call { + return &MockClient_Status_Call{Call: _e.mock.On("Status")} +} + +func (_c *MockClient_Status_Call) Run(run func()) *MockClient_Status_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockClient_Status_Call) Return(_a0 client.SubResourceWriter) *MockClient_Status_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Status_Call) RunAndReturn(run func() client.SubResourceWriter) *MockClient_Status_Call { + _c.Call.Return(run) + return _c +} + +// SubResource provides a mock function with given fields: subResource +func (_m *MockClient) SubResource(subResource string) client.SubResourceClient { + ret := _m.Called(subResource) + + var r0 client.SubResourceClient + if rf, ok := ret.Get(0).(func(string) client.SubResourceClient); ok { + r0 = rf(subResource) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(client.SubResourceClient) + } + } + + return r0 +} + +// MockClient_SubResource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubResource' +type MockClient_SubResource_Call struct { + *mock.Call +} + +// SubResource is a helper method to define mock.On call +// - subResource string +func (_e *MockClient_Expecter) SubResource(subResource interface{}) *MockClient_SubResource_Call { + return &MockClient_SubResource_Call{Call: _e.mock.On("SubResource", subResource)} +} + +func (_c *MockClient_SubResource_Call) Run(run func(subResource string)) *MockClient_SubResource_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockClient_SubResource_Call) Return(_a0 client.SubResourceClient) *MockClient_SubResource_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_SubResource_Call) RunAndReturn(run func(string) client.SubResourceClient) *MockClient_SubResource_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: ctx, obj, opts +func (_m *MockClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, obj) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.UpdateOption) error); ok { + r0 = rf(ctx, obj, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type MockClient_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - ctx context.Context +// - obj client.Object +// - opts ...client.UpdateOption +func (_e *MockClient_Expecter) Update(ctx interface{}, obj interface{}, opts ...interface{}) *MockClient_Update_Call { + return &MockClient_Update_Call{Call: _e.mock.On("Update", + append([]interface{}{ctx, obj}, opts...)...)} +} + +func (_c *MockClient_Update_Call) Run(run func(ctx context.Context, obj client.Object, opts ...client.UpdateOption)) *MockClient_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]client.UpdateOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(client.UpdateOption) + } + } + run(args[0].(context.Context), args[1].(client.Object), variadicArgs...) + }) + return _c +} + +func (_c *MockClient_Update_Call) Return(_a0 error) *MockClient_Update_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_Update_Call) RunAndReturn(run func(context.Context, client.Object, ...client.UpdateOption) error) *MockClient_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewMockClient creates a new instance of MockClient. 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 NewMockClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockClient { + mock := &MockClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/pkg/reconcilers/token/reconciler.go b/controllers/pkg/reconcilers/token/reconciler.go index fd050537..4c36f38d 100644 --- a/controllers/pkg/reconcilers/token/reconciler.go +++ b/controllers/pkg/reconcilers/token/reconciler.go @@ -45,7 +45,6 @@ func init() { const ( finalizer = "infra.nephio.org/finalizer" // errors - errGetCr = "cannot get cr" errUpdateStatus = "cannot update status" ) @@ -104,10 +103,9 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } // check if client exists otherwise retry - giteaClient := r.giteaClient.Get() - if giteaClient == nil { + if !r.giteaClient.IsInitialized() { err := fmt.Errorf("gitea server unreachable") - log.Error(err, "cannot connect to gitea server") + log.Error(err, "cannot connect to git server") cr.SetConditions(infrav1alpha1.Failed(err.Error())) return ctrl.Result{Requeue: true}, errors.Wrap(r.Status().Update(ctx, cr), errUpdateStatus) } @@ -119,6 +117,7 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // when successful remove the finalizer if cr.Spec.Lifecycle.DeletionPolicy == commonv1alpha1.DeletionDelete { if err := r.deleteToken(ctx, r.giteaClient, cr); err != nil { + log.Error(err, "cannot delete token in git server") return ctrl.Result{Requeue: true}, errors.Wrap(r.Status().Update(ctx, cr), errUpdateStatus) } } @@ -141,24 +140,24 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } // create token and secret - if err := r.createToken(ctx, giteaClient, cr); err != nil { + if err := r.createToken(ctx, r.giteaClient, cr); err != nil { return ctrl.Result{Requeue: true}, errors.Wrap(r.Status().Update(ctx, cr), errUpdateStatus) } cr.SetConditions(infrav1alpha1.Ready()) return ctrl.Result{}, errors.Wrap(r.Status().Update(ctx, cr), errUpdateStatus) } -func (r *reconciler) createToken(ctx context.Context, giteaClient *gitea.Client, cr *infrav1alpha1.Token) error { +func (r *reconciler) createToken(ctx context.Context, giteaClient giteaclient.GiteaClient, cr *infrav1alpha1.Token) error { log := log.FromContext(ctx) tokens, _, err := giteaClient.ListAccessTokens(gitea.ListAccessTokensOptions{}) if err != nil { - log.Error(err, "cannot list repo") + log.Error(err, "cannot list tokens") cr.SetConditions(infrav1alpha1.Failed(err.Error())) return err } tokenFound := false - for _, repo := range tokens { - if repo.Name == cr.GetTokenName() { + for _, token := range tokens { + if token.Name == cr.GetTokenName() { tokenFound = true break } diff --git a/controllers/pkg/reconcilers/token/reconciler_test.go b/controllers/pkg/reconcilers/token/reconciler_test.go index b2967838..08b426e0 100644 --- a/controllers/pkg/reconcilers/token/reconciler_test.go +++ b/controllers/pkg/reconcilers/token/reconciler_test.go @@ -17,54 +17,59 @@ package token import ( "context" "fmt" - "github.com/go-logr/logr" + "testing" + + "code.gitea.io/sdk/gitea" + + infrav1alpha1 "github.com/nephio-project/api/infra/v1alpha1" "github.com/nephio-project/nephio/controllers/pkg/giteaclient" "github.com/nephio-project/nephio/controllers/pkg/resource" + "github.com/nephio-project/nephio/testing/mockeryutils" "github.com/stretchr/testify/mock" - "sigs.k8s.io/controller-runtime/pkg/log" - "testing" - infrav1alpha1 "github.com/nephio-project/api/infra/v1alpha1" + "github.com/nephio-project/nephio/controllers/pkg/mocks/external/client" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1 "k8s.io/api/core/v1" ) +type fields struct { + APIPatchingApplicator resource.APIPatchingApplicator + giteaClient giteaclient.GiteaClient + finalizer *resource.APIFinalizer +} +type args struct { + ctx context.Context + giteaClient giteaclient.GiteaClient + cr *infrav1alpha1.Token +} +type tokenTests struct { + name string + fields fields + args args + mocks []mockeryutils.MockHelper + wantErr bool +} + func TestDeleteToken(t *testing.T) { - type mockHelper struct { - methodName string - argType []string - retArgList []interface{} - } - type fields struct { - APIPatchingApplicator resource.APIPatchingApplicator - giteaClient giteaclient.GiteaClient - finalizer *resource.APIFinalizer - l logr.Logger - } - type args struct { - ctx context.Context - giteaClient giteaclient.GiteaClient - cr *infrav1alpha1.Token - } - tests := []struct { - name string - fields fields - args args - mocks []mockHelper - wantErr bool - }{ + tests := []tokenTests { { name: "Delete Access token reports error", - fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(nil)}, + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil}, args: args{nil, nil, &infrav1alpha1.Token{}}, - mocks: []mockHelper{ - {"DeleteAccessToken", []string{"string"}, []interface{}{nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed")}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "DeleteAccessToken", + ArgType: []string{"string"}, + RetArgList: []interface{}{nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed")}}, }, wantErr: true, }, { name: "Delete Access token success", - fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(nil)}, + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil}, args: args{nil, nil, &infrav1alpha1.Token{}}, - mocks: []mockHelper{ - {"DeleteAccessToken", []string{"string"}, []interface{}{nil, nil}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "DeleteAccessToken", + ArgType: []string{"string"}, + RetArgList: []interface{}{nil, nil}}, }, wantErr: false, }, @@ -76,19 +81,8 @@ func TestDeleteToken(t *testing.T) { giteaClient: tt.fields.giteaClient, finalizer: tt.fields.finalizer, } - // The below block being setup and processing of mocks before invoking the function to be tested - mockGClient := new(giteaclient.MockGiteaClient) - tt.args.giteaClient = mockGClient - tt.fields.giteaClient = mockGClient - for counter := range tt.mocks { - call := mockGClient.Mock.On(tt.mocks[counter].methodName) - for _, arg := range tt.mocks[counter].argType { - call.Arguments = append(call.Arguments, mock.AnythingOfType(arg)) - } - for _, ret := range tt.mocks[counter].retArgList { - call.ReturnArguments = append(call.ReturnArguments, ret) - } - } + + initMockeryMocks(&tt) if err := r.deleteToken(tt.args.ctx, tt.args.giteaClient, tt.args.cr); (err != nil) != tt.wantErr { t.Errorf("deleteToken() error = %v, wantErr %v", err, tt.wantErr) @@ -96,3 +90,123 @@ func TestDeleteToken(t *testing.T) { }) } } + +func TestCreateToken(t *testing.T) { + + clientMock := new(mocks.MockClient) + clientMock.On("Get", nil, mock.AnythingOfType("types.NamespacedName"), mock.AnythingOfType("*v1.Secret")).Return(nil).Run(func(args mock.Arguments) {}) + clientMock.On("Patch", nil, mock.AnythingOfType("*v1.Secret"), mock.AnythingOfType("*resource.patch")).Return(nil).Run(func(args mock.Arguments) {}) + + tests := []tokenTests { + { + name: "Create Access token reports user auth error", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil}, + args: args{nil, nil, &infrav1alpha1.Token{}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "ListAccessTokens", + ArgType: []string{"gitea.ListAccessTokensOptions"}, + RetArgList: []interface{}{nil, nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed")}}, + }, + wantErr: true, + }, + { + name: "Create Access token already exists", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil}, + args: args{nil, nil, &infrav1alpha1.Token{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-ns", + Name: "test-token", + + }}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "ListAccessTokens", + ArgType: []string{"gitea.ListAccessTokensOptions"}, + RetArgList: []interface{}{[]*gitea.AccessToken{ + {ID: 123, + Name: "test-token-test-ns",}, + }, nil, nil}}, + }, + wantErr: false, + }, + { + name: "Create Access token reports user info not found", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil}, + args: args{nil, nil, &infrav1alpha1.Token{}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "ListAccessTokens", + ArgType: []string{"gitea.ListAccessTokensOptions"}, + RetArgList: []interface{}{[]*gitea.AccessToken{ + {ID: 123, + Name: "test-token-test-ns",}, + }, nil, nil}}, + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{nil, nil, fmt.Errorf("error getting User Information")}}, + }, + wantErr: true, + }, + { + name: "Create Access token reports failed to create", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil}, + args: args{nil, nil, &infrav1alpha1.Token{}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "ListAccessTokens", + ArgType: []string{"gitea.ListAccessTokensOptions"}, + RetArgList: []interface{}{[]*gitea.AccessToken{ + {ID: 123, + Name: "test-token-test-ns",}, + }, nil, nil}}, + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "CreateAccessToken", + ArgType: []string{"gitea.CreateAccessTokenOption"}, + RetArgList: []interface{}{&gitea.AccessToken{}, nil, fmt.Errorf("failed to create token")}}, + }, + wantErr: true, + }, + { + name: "Create Access token reports success", + fields: fields{resource.NewAPIPatchingApplicator(clientMock), nil, nil}, + args: args{nil, nil, &infrav1alpha1.Token{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-ns", + Name: "test-token", + + }}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "ListAccessTokens", ArgType: []string{"gitea.ListAccessTokensOptions"}, RetArgList: []interface{}{[]*gitea.AccessToken{}, nil, nil}}, + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "CreateAccessToken", + ArgType: []string{"gitea.CreateAccessTokenOption"}, + RetArgList: []interface{}{&gitea.AccessToken{ID: 123, + Name: "test-token-test-ns"}, nil, nil}}, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &reconciler{ + APIPatchingApplicator: tt.fields.APIPatchingApplicator, + giteaClient: tt.fields.giteaClient, + finalizer: tt.fields.finalizer, + } + + initMockeryMocks(&tt) + + if err := r.createToken(tt.args.ctx, tt.args.giteaClient, tt.args.cr); (err != nil) != tt.wantErr { + t.Errorf("createToken() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func initMockeryMocks(tt *tokenTests) { + mockGiteaClient := new(giteaclient.MockGiteaClient) + tt.args.giteaClient = mockGiteaClient + tt.fields.giteaClient = mockGiteaClient + mockeryutils.InitMocks(&mockGiteaClient.Mock, tt.mocks) +} \ No newline at end of file