From 3ddd4e2dad2846c196d18e5793a7b4cc8e67481b Mon Sep 17 00:00:00 2001 From: Liam Fallon <35595825+liamfallon@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:02:46 +0000 Subject: [PATCH] Converted Repository operator tests to Mockery (#461) This PR uses the approach and code described by @vjayaramrh in https://github.com/nephio-project/nephio/pull/441 to replace the unit tests for the Repository operator. This PR replaces all the unit tests with Mockery implementations. --- .mockery.yaml | 6 + .../pkg/giteaclient/mock_GiteaClient.go | 464 ++++++++++++++++++ controllers/pkg/go.mod | 4 +- controllers/pkg/go.sum | 6 +- .../reconcilers/repository/reconciler_test.go | 353 +++++++------ operators/nephio-controller-manager/go.mod | 3 + operators/nephio-controller-manager/go.sum | 4 +- testing/mockeryutils/Makefile | 18 +- 8 files changed, 692 insertions(+), 166 deletions(-) create mode 100644 .mockery.yaml create mode 100644 controllers/pkg/giteaclient/mock_GiteaClient.go diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 00000000..7baec8e4 --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,6 @@ +packages: + github.com/nephio-project/nephio/controllers/pkg/giteaclient: + interfaces: + GiteaClient: + config: + dir: "{{.InterfaceDir}}" \ No newline at end of file diff --git a/controllers/pkg/giteaclient/mock_GiteaClient.go b/controllers/pkg/giteaclient/mock_GiteaClient.go new file mode 100644 index 00000000..20aacf2d --- /dev/null +++ b/controllers/pkg/giteaclient/mock_GiteaClient.go @@ -0,0 +1,464 @@ +// Code generated by mockery v2.37.1. DO NOT EDIT. + +package giteaclient + +import ( + context "context" + + gitea "code.gitea.io/sdk/gitea" + + mock "github.com/stretchr/testify/mock" +) + +// MockGiteaClient is an autogenerated mock type for the GiteaClient type +type MockGiteaClient struct { + mock.Mock +} + +type MockGiteaClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockGiteaClient) EXPECT() *MockGiteaClient_Expecter { + return &MockGiteaClient_Expecter{mock: &_m.Mock} +} + +// 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) + + var r0 *gitea.Repository + var r1 *gitea.Response + var r2 error + if rf, ok := ret.Get(0).(func(gitea.CreateRepoOption) (*gitea.Repository, *gitea.Response, error)); ok { + return rf(createRepoOption) + } + if rf, ok := ret.Get(0).(func(gitea.CreateRepoOption) *gitea.Repository); ok { + r0 = rf(createRepoOption) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.Repository) + } + } + + if rf, ok := ret.Get(1).(func(gitea.CreateRepoOption) *gitea.Response); ok { + r1 = rf(createRepoOption) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*gitea.Response) + } + } + + if rf, ok := ret.Get(2).(func(gitea.CreateRepoOption) error); ok { + r2 = rf(createRepoOption) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockGiteaClient_CreateRepo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateRepo' +type MockGiteaClient_CreateRepo_Call struct { + *mock.Call +} + +// CreateRepo is a helper method to define mock.On call +// - createRepoOption gitea.CreateRepoOption +func (_e *MockGiteaClient_Expecter) CreateRepo(createRepoOption interface{}) *MockGiteaClient_CreateRepo_Call { + return &MockGiteaClient_CreateRepo_Call{Call: _e.mock.On("CreateRepo", createRepoOption)} +} + +func (_c *MockGiteaClient_CreateRepo_Call) Run(run func(createRepoOption gitea.CreateRepoOption)) *MockGiteaClient_CreateRepo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(gitea.CreateRepoOption)) + }) + return _c +} + +func (_c *MockGiteaClient_CreateRepo_Call) Return(_a0 *gitea.Repository, _a1 *gitea.Response, _a2 error) *MockGiteaClient_CreateRepo_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockGiteaClient_CreateRepo_Call) RunAndReturn(run func(gitea.CreateRepoOption) (*gitea.Repository, *gitea.Response, error)) *MockGiteaClient_CreateRepo_Call { + _c.Call.Return(run) + return _c +} + +// DeleteRepo provides a mock function with given fields: owner, repo +func (_m *MockGiteaClient) DeleteRepo(owner string, repo string) (*gitea.Response, error) { + ret := _m.Called(owner, repo) + + var r0 *gitea.Response + var r1 error + if rf, ok := ret.Get(0).(func(string, string) (*gitea.Response, error)); ok { + return rf(owner, repo) + } + if rf, ok := ret.Get(0).(func(string, string) *gitea.Response); ok { + r0 = rf(owner, repo) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.Response) + } + } + + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(owner, repo) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockGiteaClient_DeleteRepo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteRepo' +type MockGiteaClient_DeleteRepo_Call struct { + *mock.Call +} + +// DeleteRepo is a helper method to define mock.On call +// - owner string +// - repo string +func (_e *MockGiteaClient_Expecter) DeleteRepo(owner interface{}, repo interface{}) *MockGiteaClient_DeleteRepo_Call { + return &MockGiteaClient_DeleteRepo_Call{Call: _e.mock.On("DeleteRepo", owner, repo)} +} + +func (_c *MockGiteaClient_DeleteRepo_Call) Run(run func(owner string, repo string)) *MockGiteaClient_DeleteRepo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *MockGiteaClient_DeleteRepo_Call) Return(_a0 *gitea.Response, _a1 error) *MockGiteaClient_DeleteRepo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockGiteaClient_DeleteRepo_Call) RunAndReturn(run func(string, string) (*gitea.Response, error)) *MockGiteaClient_DeleteRepo_Call { + _c.Call.Return(run) + return _c +} + +// EditRepo provides a mock function with given fields: userName, repoCRName, editRepoOption +func (_m *MockGiteaClient) EditRepo(userName string, repoCRName string, editRepoOption gitea.EditRepoOption) (*gitea.Repository, *gitea.Response, error) { + ret := _m.Called(userName, repoCRName, editRepoOption) + + var r0 *gitea.Repository + var r1 *gitea.Response + var r2 error + if rf, ok := ret.Get(0).(func(string, string, gitea.EditRepoOption) (*gitea.Repository, *gitea.Response, error)); ok { + return rf(userName, repoCRName, editRepoOption) + } + if rf, ok := ret.Get(0).(func(string, string, gitea.EditRepoOption) *gitea.Repository); ok { + r0 = rf(userName, repoCRName, editRepoOption) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.Repository) + } + } + + if rf, ok := ret.Get(1).(func(string, string, gitea.EditRepoOption) *gitea.Response); ok { + r1 = rf(userName, repoCRName, editRepoOption) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*gitea.Response) + } + } + + if rf, ok := ret.Get(2).(func(string, string, gitea.EditRepoOption) error); ok { + r2 = rf(userName, repoCRName, editRepoOption) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockGiteaClient_EditRepo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EditRepo' +type MockGiteaClient_EditRepo_Call struct { + *mock.Call +} + +// EditRepo is a helper method to define mock.On call +// - userName string +// - repoCRName string +// - editRepoOption gitea.EditRepoOption +func (_e *MockGiteaClient_Expecter) EditRepo(userName interface{}, repoCRName interface{}, editRepoOption interface{}) *MockGiteaClient_EditRepo_Call { + return &MockGiteaClient_EditRepo_Call{Call: _e.mock.On("EditRepo", userName, repoCRName, editRepoOption)} +} + +func (_c *MockGiteaClient_EditRepo_Call) Run(run func(userName string, repoCRName string, editRepoOption gitea.EditRepoOption)) *MockGiteaClient_EditRepo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string), args[2].(gitea.EditRepoOption)) + }) + return _c +} + +func (_c *MockGiteaClient_EditRepo_Call) Return(_a0 *gitea.Repository, _a1 *gitea.Response, _a2 error) *MockGiteaClient_EditRepo_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockGiteaClient_EditRepo_Call) RunAndReturn(run func(string, string, gitea.EditRepoOption) (*gitea.Repository, *gitea.Response, error)) *MockGiteaClient_EditRepo_Call { + _c.Call.Return(run) + return _c +} + +// Get provides a mock function with given fields: +func (_m *MockGiteaClient) Get() *gitea.Client { + ret := _m.Called() + + var r0 *gitea.Client + if rf, ok := ret.Get(0).(func() *gitea.Client); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.Client) + } + } + + return r0 +} + +// MockGiteaClient_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type MockGiteaClient_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +func (_e *MockGiteaClient_Expecter) Get() *MockGiteaClient_Get_Call { + return &MockGiteaClient_Get_Call{Call: _e.mock.On("Get")} +} + +func (_c *MockGiteaClient_Get_Call) Run(run func()) *MockGiteaClient_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockGiteaClient_Get_Call) Return(_a0 *gitea.Client) *MockGiteaClient_Get_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockGiteaClient_Get_Call) RunAndReturn(run func() *gitea.Client) *MockGiteaClient_Get_Call { + _c.Call.Return(run) + return _c +} + +// GetMyUserInfo provides a mock function with given fields: +func (_m *MockGiteaClient) GetMyUserInfo() (*gitea.User, *gitea.Response, error) { + ret := _m.Called() + + var r0 *gitea.User + var r1 *gitea.Response + var r2 error + if rf, ok := ret.Get(0).(func() (*gitea.User, *gitea.Response, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *gitea.User); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.User) + } + } + + if rf, ok := ret.Get(1).(func() *gitea.Response); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*gitea.Response) + } + } + + if rf, ok := ret.Get(2).(func() error); ok { + r2 = rf() + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockGiteaClient_GetMyUserInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMyUserInfo' +type MockGiteaClient_GetMyUserInfo_Call struct { + *mock.Call +} + +// GetMyUserInfo is a helper method to define mock.On call +func (_e *MockGiteaClient_Expecter) GetMyUserInfo() *MockGiteaClient_GetMyUserInfo_Call { + return &MockGiteaClient_GetMyUserInfo_Call{Call: _e.mock.On("GetMyUserInfo")} +} + +func (_c *MockGiteaClient_GetMyUserInfo_Call) Run(run func()) *MockGiteaClient_GetMyUserInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockGiteaClient_GetMyUserInfo_Call) Return(_a0 *gitea.User, _a1 *gitea.Response, _a2 error) *MockGiteaClient_GetMyUserInfo_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockGiteaClient_GetMyUserInfo_Call) RunAndReturn(run func() (*gitea.User, *gitea.Response, error)) *MockGiteaClient_GetMyUserInfo_Call { + _c.Call.Return(run) + return _c +} + +// GetRepo provides a mock function with given fields: userName, repoCRName +func (_m *MockGiteaClient) GetRepo(userName string, repoCRName string) (*gitea.Repository, *gitea.Response, error) { + ret := _m.Called(userName, repoCRName) + + var r0 *gitea.Repository + var r1 *gitea.Response + var r2 error + if rf, ok := ret.Get(0).(func(string, string) (*gitea.Repository, *gitea.Response, error)); ok { + return rf(userName, repoCRName) + } + if rf, ok := ret.Get(0).(func(string, string) *gitea.Repository); ok { + r0 = rf(userName, repoCRName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitea.Repository) + } + } + + if rf, ok := ret.Get(1).(func(string, string) *gitea.Response); ok { + r1 = rf(userName, repoCRName) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*gitea.Response) + } + } + + if rf, ok := ret.Get(2).(func(string, string) error); ok { + r2 = rf(userName, repoCRName) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockGiteaClient_GetRepo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRepo' +type MockGiteaClient_GetRepo_Call struct { + *mock.Call +} + +// GetRepo is a helper method to define mock.On call +// - userName string +// - repoCRName string +func (_e *MockGiteaClient_Expecter) GetRepo(userName interface{}, repoCRName interface{}) *MockGiteaClient_GetRepo_Call { + return &MockGiteaClient_GetRepo_Call{Call: _e.mock.On("GetRepo", userName, repoCRName)} +} + +func (_c *MockGiteaClient_GetRepo_Call) Run(run func(userName string, repoCRName string)) *MockGiteaClient_GetRepo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *MockGiteaClient_GetRepo_Call) Return(_a0 *gitea.Repository, _a1 *gitea.Response, _a2 error) *MockGiteaClient_GetRepo_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockGiteaClient_GetRepo_Call) RunAndReturn(run func(string, string) (*gitea.Repository, *gitea.Response, error)) *MockGiteaClient_GetRepo_Call { + _c.Call.Return(run) + return _c +} + +// IsInitialized provides a mock function with given fields: +func (_m *MockGiteaClient) IsInitialized() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockGiteaClient_IsInitialized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsInitialized' +type MockGiteaClient_IsInitialized_Call struct { + *mock.Call +} + +// IsInitialized is a helper method to define mock.On call +func (_e *MockGiteaClient_Expecter) IsInitialized() *MockGiteaClient_IsInitialized_Call { + return &MockGiteaClient_IsInitialized_Call{Call: _e.mock.On("IsInitialized")} +} + +func (_c *MockGiteaClient_IsInitialized_Call) Run(run func()) *MockGiteaClient_IsInitialized_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockGiteaClient_IsInitialized_Call) Return(_a0 bool) *MockGiteaClient_IsInitialized_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockGiteaClient_IsInitialized_Call) RunAndReturn(run func() bool) *MockGiteaClient_IsInitialized_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) +} + +// MockGiteaClient_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type MockGiteaClient_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockGiteaClient_Expecter) Start(ctx interface{}) *MockGiteaClient_Start_Call { + return &MockGiteaClient_Start_Call{Call: _e.mock.On("Start", ctx)} +} + +func (_c *MockGiteaClient_Start_Call) Run(run func(ctx context.Context)) *MockGiteaClient_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockGiteaClient_Start_Call) Return() *MockGiteaClient_Start_Call { + _c.Call.Return() + return _c +} + +func (_c *MockGiteaClient_Start_Call) RunAndReturn(run func(context.Context)) *MockGiteaClient_Start_Call { + _c.Call.Return(run) + return _c +} + +// NewMockGiteaClient creates a new instance of MockGiteaClient. 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 NewMockGiteaClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockGiteaClient { + mock := &MockGiteaClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controllers/pkg/go.mod b/controllers/pkg/go.mod index feb89ff3..bbd98b22 100644 --- a/controllers/pkg/go.mod +++ b/controllers/pkg/go.mod @@ -25,11 +25,12 @@ require ( github.com/nephio-project/nephio/krm-functions/ipam-fn v0.0.0-00010101000000-000000000000 github.com/nephio-project/nephio/krm-functions/lib v0.0.0-20230605213956-a1e470f419a4 github.com/nephio-project/nephio/krm-functions/vlan-fn v0.0.0-00010101000000-000000000000 + github.com/nephio-project/nephio/testing/mockeryutils v0.0.0-20240112001535-96b08ff4acb3 github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4 github.com/openconfig/ygot v0.28.3 github.com/pkg/errors v0.9.1 github.com/srl-labs/ygotsrl/v22 v22.11.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 k8s.io/api v0.27.3 k8s.io/apimachinery v0.27.3 k8s.io/client-go v0.27.2 @@ -83,6 +84,7 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect golang.org/x/crypto v0.9.0 // indirect diff --git a/controllers/pkg/go.sum b/controllers/pkg/go.sum index 47b034a9..9f220987 100644 --- a/controllers/pkg/go.sum +++ b/controllers/pkg/go.sum @@ -152,6 +152,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nephio-project/api v1.0.1-0.20231127124455-cf14bd57b08d h1:hs1ml1d3MaLBLn5yhfz2RPA9B8VGXMGJhZSjyDXJDQY= github.com/nephio-project/api v1.0.1-0.20231127124455-cf14bd57b08d/go.mod h1:9w+JbXeyiT3KZrrXab0pzaWtiUk4upvgLzpqOtSmbpI= +github.com/nephio-project/nephio/testing/mockeryutils v0.0.0-20240112001535-96b08ff4acb3 h1:RNwnrA6AmFLFZkmJa6rVX6PTpf4QxlCF5oYWdpsap1g= +github.com/nephio-project/nephio/testing/mockeryutils v0.0.0-20240112001535-96b08ff4acb3/go.mod h1:mQqKgxdpWotKvgZKbfFHPK0gLJ4Z9CsJb/tEUoeDpLs= github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4 h1:4v0n24tsumwuz1BDGKoGWxZMFtqAlYpI87gE/enMUUI= github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4/go.mod h1:ZVMmhD6jllAAO3YGIZFXUQbKRtEiIYgZ772bn/1GVz4= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -200,8 +202,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/controllers/pkg/reconcilers/repository/reconciler_test.go b/controllers/pkg/reconcilers/repository/reconciler_test.go index eda325fa..366ce613 100644 --- a/controllers/pkg/reconcilers/repository/reconciler_test.go +++ b/controllers/pkg/reconcilers/repository/reconciler_test.go @@ -16,54 +16,37 @@ package repository import ( "context" - "errors" + "fmt" "testing" + "github.com/go-logr/logr" + "github.com/nephio-project/nephio/controllers/pkg/giteaclient" + "github.com/nephio-project/nephio/controllers/pkg/resource" + "github.com/nephio-project/nephio/testing/mockeryutils" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/log" + "code.gitea.io/sdk/gitea" infrav1alpha1 "github.com/nephio-project/api/infra/v1alpha1" - "github.com/stretchr/testify/require" ) -type GiteaClientMock struct { -} - -type NephioGiteaClientMock struct { - myUserInfoError error - deleteRepoError error - getRepoError error - createRepoError error - editRepoError error -} - -func (gc NephioGiteaClientMock) IsInitialized() bool { - return true -} - -func (gc NephioGiteaClientMock) Get() *gitea.Client { - return nil -} - -func (gc NephioGiteaClientMock) Start(ctx context.Context) { -} - -func (gc NephioGiteaClientMock) GetMyUserInfo() (*gitea.User, *gitea.Response, error) { - return &gitea.User{}, &gitea.Response{}, gc.myUserInfoError +type fields struct { + APIPatchingApplicator resource.APIPatchingApplicator + giteaClient giteaclient.GiteaClient + finalizer *resource.APIFinalizer + l logr.Logger } - -func (gc NephioGiteaClientMock) DeleteRepo(owner string, repo string) (*gitea.Response, error) { - return nil, gc.deleteRepoError -} - -func (gc NephioGiteaClientMock) GetRepo(userName string, repoCRName string) (*gitea.Repository, *gitea.Response, error) { - return nil, nil, gc.getRepoError +type args struct { + ctx context.Context + giteaClient giteaclient.GiteaClient + cr *infrav1alpha1.Repository } - -func (gc NephioGiteaClientMock) CreateRepo(createRepoOption gitea.CreateRepoOption) (*gitea.Repository, *gitea.Response, error) { - return &gitea.Repository{}, nil, gc.createRepoError -} - -func (gc NephioGiteaClientMock) EditRepo(userName string, repoCRName string, editRepoOption gitea.EditRepoOption) (*gitea.Repository, *gitea.Response, error) { - return &gitea.Repository{}, nil, gc.editRepoError +type repoTest struct { + name string + fields fields + args args + mocks []mockeryutils.MockHelper + wantErr bool } func TestUpsertRepo(t *testing.T) { @@ -71,132 +54,210 @@ func TestUpsertRepo(t *testing.T) { dummyBool := true dummyTrustModel := infrav1alpha1.TrustModel("Trust Model") - testCases := map[string]struct { - ctx context.Context - giteaClient NephioGiteaClientMock - cr infrav1alpha1.Repository - expectedErr error - }{ - "User Info reports error": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - myUserInfoError: errors.New("Error getting User Information"), - }, - cr: infrav1alpha1.Repository{}, - expectedErr: errors.New("Error getting User Information"), + tests := []repoTest{ + { + name: "User Info reports error", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{nil, nil, &infrav1alpha1.Repository{}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{nil, nil, fmt.Errorf("error getting User Information")}}, + }, + wantErr: true, }, - "Repo exists, cr fields blank": { - ctx: nil, - giteaClient: NephioGiteaClientMock{}, - cr: infrav1alpha1.Repository{ - Status: infrav1alpha1.RepositoryStatus{}, + { + name: "Repo exists, cr spec fields blank", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{nil, nil, &infrav1alpha1.Repository{Status: infrav1alpha1.RepositoryStatus{}}}, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "GetRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, + {MethodName: "EditRepo", ArgType: []string{"string", "string", "gitea.EditRepoOption"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, }, - expectedErr: nil, + wantErr: false, }, - "Repo exists, cr fields not blank": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - editRepoError: errors.New("Repo update failed"), - }, - cr: infrav1alpha1.Repository{ - Spec: infrav1alpha1.RepositorySpec{ - Description: &dummyString, - Private: &dummyBool, + { + name: "Repo exists, cr spec fields not blank", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{ + Spec: infrav1alpha1.RepositorySpec{ + Description: &dummyString, + Private: &dummyBool, + }, + Status: infrav1alpha1.RepositoryStatus{}, }, - Status: infrav1alpha1.RepositoryStatus{}, }, - expectedErr: errors.New("Repo update failed"), + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "GetRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, + {MethodName: "EditRepo", ArgType: []string{"string", "string", "gitea.EditRepoOption"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, + }, + wantErr: false, }, - "Repo exists, update fails": { - ctx: nil, - giteaClient: NephioGiteaClientMock{}, - cr: infrav1alpha1.Repository{ - Status: infrav1alpha1.RepositoryStatus{}, + { + name: "Repo exists, update fails", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{}, + }, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "GetRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, + {MethodName: "EditRepo", ArgType: []string{"string", "string", + "gitea.EditRepoOption"}, RetArgList: []interface{}{&gitea.Repository{}, nil, fmt.Errorf("error updating repo")}}, }, - expectedErr: nil, + wantErr: true, }, - "Create repo: cr fields not blank": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - getRepoError: errors.New("Repo does not exist"), - }, - cr: infrav1alpha1.Repository{ - Spec: infrav1alpha1.RepositorySpec{ - Description: &dummyString, - Private: &dummyBool, - IssueLabels: &dummyString, - Gitignores: &dummyString, - License: &dummyString, - Readme: &dummyString, - DefaultBranch: &dummyString, - TrustModel: &dummyTrustModel, + { + name: "Create repo: cr fields not blank", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{ + Spec: infrav1alpha1.RepositorySpec{ + Description: &dummyString, + Private: &dummyBool, + IssueLabels: &dummyString, + Gitignores: &dummyString, + License: &dummyString, + Readme: &dummyString, + DefaultBranch: &dummyString, + TrustModel: &dummyTrustModel, + }, }, }, - expectedErr: nil, - }, - "Create repo: cr fields blank": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - getRepoError: errors.New("Repo does not exist"), + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "GetRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Repository{}, nil, fmt.Errorf("repo does not exist")}}, + {MethodName: "CreateRepo", ArgType: []string{"gitea.CreateRepoOption"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, }, - cr: infrav1alpha1.Repository{}, - expectedErr: nil, + wantErr: false, }, - "Create repo: fails": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - getRepoError: errors.New("Repo does not exist"), - createRepoError: errors.New("Error creating repo"), - }, - cr: infrav1alpha1.Repository{}, - expectedErr: errors.New("Error creating repo"), + { + name: "Create repo: cr fields blank", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{}, + }, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "GetRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Repository{}, nil, fmt.Errorf("repo does not exist")}}, + {MethodName: "CreateRepo", ArgType: []string{"gitea.CreateRepoOption"}, RetArgList: []interface{}{&gitea.Repository{}, nil, nil}}, + }, + wantErr: false, }, - } - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - r := reconciler{} - err := r.upsertRepo(tc.ctx, tc.giteaClient, &tc.cr) - require.Equal(t, tc.expectedErr, err) + { + name: "Create repo: fails", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{}, + }, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "GetRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Repository{}, nil, fmt.Errorf("repo does not exist")}}, + {MethodName: "CreateRepo", ArgType: []string{"gitea.CreateRepoOption"}, RetArgList: []interface{}{&gitea.Repository{}, nil, fmt.Errorf("repo creation fails")}}, + }, + wantErr: true, + }} + 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.upsertRepo(tt.args.ctx, tt.args.giteaClient, tt.args.cr); (err != nil) != tt.wantErr { + t.Errorf("upsertRepo() error = %v, wantErr %v", err, tt.wantErr) + } }) } } func TestDeleteRepo(t *testing.T) { - - testCases := map[string]struct { - ctx context.Context - giteaClient NephioGiteaClientMock - cr infrav1alpha1.Repository - expectedErr error - }{ - "User Info and Delete repo both work": { - ctx: nil, - giteaClient: NephioGiteaClientMock{}, - cr: infrav1alpha1.Repository{}, - expectedErr: nil, - }, - "User Info reports error": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - myUserInfoError: errors.New("Error getting User Information"), + tests := []repoTest{ + { + name: "User Info and Delete Repo both OK", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{ + ObjectMeta: v1.ObjectMeta{ + Name: "repo-name", + }, + }, }, - cr: infrav1alpha1.Repository{}, - expectedErr: errors.New("Error getting User Information"), - }, - "Delete repo reports error": { - ctx: nil, - giteaClient: NephioGiteaClientMock{ - deleteRepoError: errors.New("Error deleting repo"), + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "DeleteRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Response{}, nil, nil}}, }, - cr: infrav1alpha1.Repository{}, - expectedErr: errors.New("Error deleting repo"), - }, - } - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - r := reconciler{} - err := r.deleteRepo(tc.ctx, tc.giteaClient, &tc.cr) - require.Equal(t, tc.expectedErr, err) + wantErr: false, + }, { + name: "User Info reports error", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{ + ObjectMeta: v1.ObjectMeta{ + Name: "repo-name", + }, + }, + }, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, fmt.Errorf("Error getting User Information")}}, + }, + wantErr: true, + }, { + name: "Delete Repo reports error", + fields: fields{resource.NewAPIPatchingApplicator(nil), nil, nil, log.FromContext(context.Background())}, + args: args{ + nil, + nil, + &infrav1alpha1.Repository{ + ObjectMeta: v1.ObjectMeta{ + Name: "repo-name", + }, + }, + }, + mocks: []mockeryutils.MockHelper{ + {MethodName: "GetMyUserInfo", ArgType: []string{}, RetArgList: []interface{}{&gitea.User{UserName: "gitea"}, nil, nil}}, + {MethodName: "DeleteRepo", ArgType: []string{"string", "string"}, RetArgList: []interface{}{&gitea.Response{}, fmt.Errorf("Error deleting repo")}}, + }, + wantErr: true, + }} + 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.deleteRepo(tt.args.ctx, tt.args.giteaClient, tt.args.cr); (err != nil) != tt.wantErr { + t.Errorf("deleteRepo() error = %v, wantErr %v", err, tt.wantErr) + } }) } } + +func initMockeryMocks(tt *repoTest) { + mockGClient := new(giteaclient.MockGiteaClient) + tt.args.giteaClient = mockGClient + tt.fields.giteaClient = mockGClient + mockeryutils.InitMocks(&mockGClient.Mock, tt.mocks) +} diff --git a/operators/nephio-controller-manager/go.mod b/operators/nephio-controller-manager/go.mod index e40f5699..32ca7aa5 100644 --- a/operators/nephio-controller-manager/go.mod +++ b/operators/nephio-controller-manager/go.mod @@ -80,12 +80,15 @@ require ( github.com/openconfig/goyang v1.4.0 // indirect github.com/openconfig/ygot v0.28.3 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/srl-labs/ygotsrl/v22 v22.11.1 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/operators/nephio-controller-manager/go.sum b/operators/nephio-controller-manager/go.sum index a579488b..6d0d44ea 100644 --- a/operators/nephio-controller-manager/go.sum +++ b/operators/nephio-controller-manager/go.sum @@ -156,6 +156,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nephio-project/api v1.0.1-0.20231127124455-cf14bd57b08d h1:hs1ml1d3MaLBLn5yhfz2RPA9B8VGXMGJhZSjyDXJDQY= github.com/nephio-project/api v1.0.1-0.20231127124455-cf14bd57b08d/go.mod h1:9w+JbXeyiT3KZrrXab0pzaWtiUk4upvgLzpqOtSmbpI= +github.com/nephio-project/nephio/testing/mockeryutils v0.0.0-20240112001535-96b08ff4acb3 h1:RNwnrA6AmFLFZkmJa6rVX6PTpf4QxlCF5oYWdpsap1g= github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4 h1:4v0n24tsumwuz1BDGKoGWxZMFtqAlYpI87gE/enMUUI= github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4/go.mod h1:ZVMmhD6jllAAO3YGIZFXUQbKRtEiIYgZ772bn/1GVz4= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -204,7 +205,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/testing/mockeryutils/Makefile b/testing/mockeryutils/Makefile index 4d044960..a3afad3b 100644 --- a/testing/mockeryutils/Makefile +++ b/testing/mockeryutils/Makefile @@ -1,19 +1,5 @@ -# Copyright 2024 The Nephio Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - .PHONY: all -all: fmt test +all: fmt lint gosec # This includes the following targets: # test, unit, unit-clean, @@ -22,4 +8,4 @@ all: fmt test include ../../default-go.mk # This includes the 'help' target that prints out all targets with their descriptions organized by categories -include ../../default-help.mk +include ../../default-help.mk \ No newline at end of file