diff --git a/.mockery.yaml b/.mockery.yaml index a389599..68c083d 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -6,4 +6,8 @@ packages: outpkg: "operator" dir: "pkg/operator" interfaces: - phaser: \ No newline at end of file + phaser: + Operator: + config: + outpkg: "mocks" + dir: "pkg/operator/mocks" \ No newline at end of file diff --git a/pkg/operator/mocks/mock_Operator.go b/pkg/operator/mocks/mock_Operator.go new file mode 100644 index 0000000..672aeec --- /dev/null +++ b/pkg/operator/mocks/mock_Operator.go @@ -0,0 +1,81 @@ +// Code generated by mockery v2.32.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + operator "github.com/trento-project/workbench/pkg/operator" +) + +// MockOperator is an autogenerated mock type for the Operator type +type MockOperator struct { + mock.Mock +} + +type MockOperator_Expecter struct { + mock *mock.Mock +} + +func (_m *MockOperator) EXPECT() *MockOperator_Expecter { + return &MockOperator_Expecter{mock: &_m.Mock} +} + +// Run provides a mock function with given fields: ctx +func (_m *MockOperator) Run(ctx context.Context) *operator.ExecutionReport { + ret := _m.Called(ctx) + + var r0 *operator.ExecutionReport + if rf, ok := ret.Get(0).(func(context.Context) *operator.ExecutionReport); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*operator.ExecutionReport) + } + } + + return r0 +} + +// MockOperator_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run' +type MockOperator_Run_Call struct { + *mock.Call +} + +// Run is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockOperator_Expecter) Run(ctx interface{}) *MockOperator_Run_Call { + return &MockOperator_Run_Call{Call: _e.mock.On("Run", ctx)} +} + +func (_c *MockOperator_Run_Call) Run(run func(ctx context.Context)) *MockOperator_Run_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockOperator_Run_Call) Return(_a0 *operator.ExecutionReport) *MockOperator_Run_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockOperator_Run_Call) RunAndReturn(run func(context.Context) *operator.ExecutionReport) *MockOperator_Run_Call { + _c.Call.Return(run) + return _c +} + +// NewMockOperator creates a new instance of MockOperator. 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 NewMockOperator(t interface { + mock.TestingT + Cleanup(func()) +}) *MockOperator { + mock := &MockOperator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/operator/registry.go b/pkg/operator/registry.go index 2ccf433..f4a064c 100644 --- a/pkg/operator/registry.go +++ b/pkg/operator/registry.go @@ -17,7 +17,7 @@ func (e *OperatorNotFoundError) Error() string { type OperatorBuilder func(operationID string, arguments OperatorArguments) Operator // map[operatorName]map[operatorVersion]OperatorBuilder -type operatorBuildersTree map[string]map[string]OperatorBuilder +type OperatorBuildersTree map[string]map[string]OperatorBuilder func extractOperatorNameAndVersion(operatorName string) (string, string, error) { parts := strings.Split(operatorName, "@") @@ -35,7 +35,13 @@ func extractOperatorNameAndVersion(operatorName string) (string, string, error) } type Registry struct { - operators operatorBuildersTree + operators OperatorBuildersTree +} + +func NewRegistry(operators OperatorBuildersTree) *Registry { + return &Registry{ + operators: operators, + } } func (m *Registry) GetOperatorBuilder(name string) (OperatorBuilder, error) { @@ -92,7 +98,7 @@ func (m *Registry) getLatestVersionForOperator(name string) (string, error) { func StandardRegistry(options ...BaseOperationOption) *Registry { return &Registry{ - operators: operatorBuildersTree{ + operators: OperatorBuildersTree{ SaptuneApplySolutionOperatorName: map[string]OperatorBuilder{ "v1": func(operationID string, arguments OperatorArguments) Operator { return NewSaptuneApplySolution(arguments, operationID, OperatorOptions[saptuneApplySolution]{ diff --git a/pkg/operator/registry_test.go b/pkg/operator/registry_test.go new file mode 100644 index 0000000..cd0d118 --- /dev/null +++ b/pkg/operator/registry_test.go @@ -0,0 +1,111 @@ +package operator_test + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/suite" + "github.com/trento-project/workbench/pkg/operator" + "github.com/trento-project/workbench/pkg/operator/mocks" +) + +type RegistryTest struct { + suite.Suite +} + +func TestRegistryTest(t *testing.T) { + suite.Run(t, new(RegistryTest)) +} + +func (suite *RegistryTest) TestRegistryAvailableOperators() { + registry := operator.NewRegistry(operator.OperatorBuildersTree{ + operator.SaptuneApplySolutionOperatorName: map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test2": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + }) + + expectedOperators := []string{ + "saptuneapplysolution - v1/v2", + "test - v1/v2", + "test2 - v1", + } + + // we sort the array in order to have consistency in the tests + // map keys are not ordered ofc + + result := registry.AvailableOperators() + sort.Strings(result) + + suite.Equal(expectedOperators, result) +} + +func (suite *RegistryTest) TestGetOperatorBuilderNotFound() { + registry := operator.NewRegistry(operator.OperatorBuildersTree{ + operator.SaptuneApplySolutionOperatorName: map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test2": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + }) + _, err := registry.GetOperatorBuilder("other@v1") + + suite.EqualError(err, "operator other@v1 not found") +} + +func (suite *RegistryTest) TestGetOperatorBuilderFoundWithVersion() { + foundOperator := mocks.NewMockOperator(suite.T()) + registry := operator.NewRegistry(operator.OperatorBuildersTree{ + operator.SaptuneApplySolutionOperatorName: map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return foundOperator }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test2": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + }) + + b, err := registry.GetOperatorBuilder("saptuneapplysolution@v1") + + suite.NoError(err) + suite.Equal(b("", nil), foundOperator) +} + +func (suite *RegistryTest) TestGetOperatorBuilderFoundWithoutVersionGetLast() { + foundOperator := mocks.NewMockOperator(suite.T()) + registry := operator.NewRegistry(operator.OperatorBuildersTree{ + operator.SaptuneApplySolutionOperatorName: map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return foundOperator }, + }, + "test": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + "v2": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + "test2": map[string]operator.OperatorBuilder{ + "v1": func(operationID string, arguments operator.OperatorArguments) operator.Operator { return nil }, + }, + }) + + b, err := registry.GetOperatorBuilder("saptuneapplysolution") + + suite.NoError(err) + suite.Equal(b("", nil), foundOperator) +}