diff --git a/components/director/go.mod b/components/director/go.mod index 1eadc4ee70..81b58a2711 100644 --- a/components/director/go.mod +++ b/components/director/go.mod @@ -9,6 +9,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/avast/retry-go/v4 v4.5.0 + github.com/davecgh/go-spew v1.1.1 github.com/dlmiddlecote/sqlstats v1.0.2 github.com/form3tech-oss/jwt-go v3.2.5+incompatible github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -58,7 +59,6 @@ require ( github.com/agnivade/levenshtein v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect diff --git a/components/director/internal/domain/application/automock/formation_service.go b/components/director/internal/domain/application/automock/formation_service.go index c9b4e58ce9..4cfab67951 100644 --- a/components/director/internal/domain/application/automock/formation_service.go +++ b/components/director/internal/domain/application/automock/formation_service.go @@ -16,36 +16,6 @@ type FormationService struct { mock.Mock } -// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, formation -func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) { - ret := _m.Called(ctx, tnt, objectID, objectType, formation) - - if len(ret) == 0 { - panic("no return value specified for AssignFormation") - } - - var r0 *model.Formation - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) (*model.Formation, error)); ok { - return rf(ctx, tnt, objectID, objectType, formation) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) *model.Formation); ok { - r0 = rf(ctx, tnt, objectID, objectType, formation) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Formation) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) error); ok { - r1 = rf(ctx, tnt, objectID, objectType, formation) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // ListFormationsForObject provides a mock function with given fields: ctx, objectID func (_m *FormationService) ListFormationsForObject(ctx context.Context, objectID string) ([]*model.Formation, error) { ret := _m.Called(ctx, objectID) diff --git a/components/director/internal/domain/application/automock/scenarios_filter_sanitizer.go b/components/director/internal/domain/application/automock/scenarios_filter_sanitizer.go index 028c2d17bc..b8e1744a2e 100644 --- a/components/director/internal/domain/application/automock/scenarios_filter_sanitizer.go +++ b/components/director/internal/domain/application/automock/scenarios_filter_sanitizer.go @@ -9,6 +9,8 @@ import ( labelfilter "github.com/kyma-incubator/compass/components/director/internal/labelfilter" mock "github.com/stretchr/testify/mock" + + model "github.com/kyma-incubator/compass/components/director/internal/model" ) // ScenariosFilterSanitizer is an autogenerated mock type for the ScenariosFilterSanitizer type @@ -16,9 +18,9 @@ type ScenariosFilterSanitizer struct { mock.Mock } -// RemoveScenarioFilter provides a mock function with given fields: ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc -func (_m *ScenariosFilterSanitizer) RemoveScenarioFilter(ctx context.Context, tenant string, filters []*labelfilter.LabelFilter, isGlobal bool, listerFunc filtersanitizer.ObjectIDListerFunc, globalListerFunc filtersanitizer.ObjectIDListerFuncGlobal) (bool, []string, []*labelfilter.LabelFilter, error) { - ret := _m.Called(ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc) +// RemoveScenarioFilter provides a mock function with given fields: ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc +func (_m *ScenariosFilterSanitizer) RemoveScenarioFilter(ctx context.Context, tenant string, filters []*labelfilter.LabelFilter, objectType model.FormationAssignmentType, isGlobal bool, listerFunc filtersanitizer.ObjectIDListerFunc, globalListerFunc filtersanitizer.ObjectIDListerFuncGlobal) (bool, []string, []*labelfilter.LabelFilter, error) { + ret := _m.Called(ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc) if len(ret) == 0 { panic("no return value specified for RemoveScenarioFilter") @@ -28,33 +30,33 @@ func (_m *ScenariosFilterSanitizer) RemoveScenarioFilter(ctx context.Context, te var r1 []string var r2 []*labelfilter.LabelFilter var r3 error - if rf, ok := ret.Get(0).(func(context.Context, string, []*labelfilter.LabelFilter, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) (bool, []string, []*labelfilter.LabelFilter, error)); ok { - return rf(ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc) + if rf, ok := ret.Get(0).(func(context.Context, string, []*labelfilter.LabelFilter, model.FormationAssignmentType, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) (bool, []string, []*labelfilter.LabelFilter, error)); ok { + return rf(ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc) } - if rf, ok := ret.Get(0).(func(context.Context, string, []*labelfilter.LabelFilter, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) bool); ok { - r0 = rf(ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc) + if rf, ok := ret.Get(0).(func(context.Context, string, []*labelfilter.LabelFilter, model.FormationAssignmentType, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) bool); ok { + r0 = rf(ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(context.Context, string, []*labelfilter.LabelFilter, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) []string); ok { - r1 = rf(ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc) + if rf, ok := ret.Get(1).(func(context.Context, string, []*labelfilter.LabelFilter, model.FormationAssignmentType, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) []string); ok { + r1 = rf(ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc) } else { if ret.Get(1) != nil { r1 = ret.Get(1).([]string) } } - if rf, ok := ret.Get(2).(func(context.Context, string, []*labelfilter.LabelFilter, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) []*labelfilter.LabelFilter); ok { - r2 = rf(ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc) + if rf, ok := ret.Get(2).(func(context.Context, string, []*labelfilter.LabelFilter, model.FormationAssignmentType, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) []*labelfilter.LabelFilter); ok { + r2 = rf(ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc) } else { if ret.Get(2) != nil { r2 = ret.Get(2).([]*labelfilter.LabelFilter) } } - if rf, ok := ret.Get(3).(func(context.Context, string, []*labelfilter.LabelFilter, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) error); ok { - r3 = rf(ctx, tenant, filters, isGlobal, listerFunc, globalListerFunc) + if rf, ok := ret.Get(3).(func(context.Context, string, []*labelfilter.LabelFilter, model.FormationAssignmentType, bool, filtersanitizer.ObjectIDListerFunc, filtersanitizer.ObjectIDListerFuncGlobal) error); ok { + r3 = rf(ctx, tenant, filters, objectType, isGlobal, listerFunc, globalListerFunc) } else { r3 = ret.Error(3) } diff --git a/components/director/internal/domain/application/service.go b/components/director/internal/domain/application/service.go index 6b01819f8c..3fc67dd940 100644 --- a/components/director/internal/domain/application/service.go +++ b/components/director/internal/domain/application/service.go @@ -120,7 +120,6 @@ type WebhookRepository interface { // //go:generate mockery --name=FormationService --output=automock --outpkg=automock --case=underscore --disable-version-string type FormationService interface { - AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) ListFormationsForObject(ctx context.Context, objectID string) ([]*model.Formation, error) ListFormationsForObjectGlobal(ctx context.Context, objectID string) ([]*model.Formation, error) ListObjectIDsOfTypeForFormations(ctx context.Context, tenantID string, formationNames []string, objectType model.FormationAssignmentType) ([]string, error) diff --git a/components/director/internal/domain/formation/assign_formation_test.go b/components/director/internal/domain/formation/assign_formation_test.go index 5887610e0d..6eb6f30be7 100644 --- a/components/director/internal/domain/formation/assign_formation_test.go +++ b/components/director/internal/domain/formation/assign_formation_test.go @@ -2,6 +2,7 @@ package formation_test import ( "context" + "encoding/json" "errors" "fmt" "testing" @@ -244,6 +245,10 @@ func TestServiceAssignFormation(t *testing.T) { } runtime := &model.Runtime{ID: RuntimeID} + configuration, err := json.Marshal("{\"key\":\"value\"}") + require.NoError(t, err) + + initialConfigurations := model.InitialConfigurations{ApplicationID: map[string]json.RawMessage{ApplicationID: configuration}} assignmentOperation := mock.MatchedBy(func(op *model.AssignmentOperationInput) bool { return op.Type == model.Assign && op.FormationAssignmentID == FormationAssignmentID && op.FormationID == FormationID && op.TriggeredBy == model.AssignObject @@ -309,7 +314,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -361,7 +366,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -430,7 +435,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedSecondFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedSecondFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments2, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments2, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -499,7 +504,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedSecondFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedSecondFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments2, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments2, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -560,7 +565,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeID, graphql.FormationObjectTypeRuntime, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeID, graphql.FormationObjectTypeRuntime, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -616,7 +621,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeID, graphql.FormationObjectTypeRuntime, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeID, graphql.FormationObjectTypeRuntime, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -674,7 +679,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeID, graphql.FormationObjectTypeRuntime, expectedSecondFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeID, graphql.FormationObjectTypeRuntime, expectedSecondFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -745,7 +750,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), assignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -802,7 +807,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), assignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -871,7 +876,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedSecondFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedSecondFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), assignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() return formationAssignmentSvc @@ -983,7 +988,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedSecondFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedSecondFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments2, nil).Once() return formationAssignmentSvc }, @@ -2104,7 +2109,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, formationInInitialState).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, formationInInitialState, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() return formationAssignmentSvc }, @@ -2156,7 +2161,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, formationInDraftState).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, formationInDraftState, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() return formationAssignmentSvc }, @@ -2234,7 +2239,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), ApplicationID).Return(nil).Once() return formationAssignmentSvc @@ -2293,7 +2298,7 @@ func TestServiceAssignFormation(t *testing.T) { NotificationServiceFN: unusedNotificationsService, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(nil, testErr).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(nil, testErr).Once() return formationAssignmentSvc }, ConstraintEngineFn: func() *automock.ConstraintEngine { @@ -2339,7 +2344,7 @@ func TestServiceAssignFormation(t *testing.T) { NotificationServiceFN: unusedNotificationsService, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(nil, testErr).Once() return formationAssignmentSvc }, @@ -2388,7 +2393,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(testErr).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), ApplicationID).Return(nil).Once() @@ -2444,7 +2449,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(nil, nil).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), RuntimeContextID).Return(nil).Once() return formationAssignmentSvc @@ -2498,7 +2503,7 @@ func TestServiceAssignFormation(t *testing.T) { NotificationServiceFN: unusedNotificationsService, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation).Return(nil, testErr).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation, initialConfigurations).Return(nil, testErr).Once() return formationAssignmentSvc }, ConstraintEngineFn: func() *automock.ConstraintEngine { @@ -2550,7 +2555,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, RuntimeContextID, graphql.FormationObjectTypeRuntimeContext, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(assignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), assignments, notifications, mock.Anything, model.AssignFormation).Return(testErr).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), RuntimeContextID).Return(nil).Once() @@ -2607,7 +2612,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(testErr).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), ApplicationID).Return(nil).Once() @@ -2664,7 +2669,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(testErr).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), ApplicationID).Return(nil).Once() @@ -2750,7 +2755,7 @@ func TestServiceAssignFormation(t *testing.T) { }, FormationAssignmentServiceFn: func() *automock.FormationAssignmentService { formationAssignmentSvc := &automock.FormationAssignmentService{} - formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation).Return(formationAssignmentInputs, nil).Once() + formationAssignmentSvc.On("GenerateAssignments", ctxWithTenantAndLoggerMatcher(), TntInternalID, ApplicationID, graphql.FormationObjectTypeApplication, expectedFormation, initialConfigurations).Return(formationAssignmentInputs, nil).Once() formationAssignmentSvc.On("PersistAssignments", txtest.CtxWithDBMatcher(), TntInternalID, formationAssignmentInputs).Return(formationAssignments, nil).Once() formationAssignmentSvc.On("ProcessFormationAssignments", txtest.CtxWithDBMatcher(), formationAssignments, notifications, mock.Anything, model.AssignFormation).Return(nil).Once() formationAssignmentSvc.On("DeleteAssignmentsForObjectID", txtest.CtxWithDBMatcher(), fixUUID(), ApplicationID).Return(nil).Once() @@ -3073,7 +3078,7 @@ func TestServiceAssignFormation(t *testing.T) { svc := formation.NewServiceWithAsaEngine(transact, applicationRepository, nil, nil, formationRepo, formationTemplateRepo, labelService, uidService, labelDefService, asaRepo, asaService, tenantSvc, runtimeRepo, runtimeContextRepo, formationAssignmentSvc, nil, nil, notificationSvc, constraintEngine, runtimeType, applicationType, asaEngine, nil, assignmentOperationService) // WHEN - actual, err := svc.AssignFormation(ctxWithTenant, TntInternalID, testCase.ObjectID, testCase.ObjectType, testCase.InputFormation) + actual, err := svc.AssignFormation(ctxWithTenant, TntInternalID, testCase.ObjectID, testCase.ObjectType, testCase.InputFormation, initialConfigurations) // THEN if testCase.ExpectedErrMessage == "" { diff --git a/components/director/internal/domain/formation/automock/formation_assignment_service.go b/components/director/internal/domain/formation/automock/formation_assignment_service.go index a6a2f43258..53ee027bde 100644 --- a/components/director/internal/domain/formation/automock/formation_assignment_service.go +++ b/components/director/internal/domain/formation/automock/formation_assignment_service.go @@ -85,9 +85,9 @@ func (_m *FormationAssignmentService) DeleteAssignmentsForObjectID(ctx context.C return r0 } -// GenerateAssignments provides a mock function with given fields: ctx, tnt, objectID, objectType, _a4 -func (_m *FormationAssignmentService) GenerateAssignments(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, _a4 *model.Formation) ([]*model.FormationAssignmentInput, error) { - ret := _m.Called(ctx, tnt, objectID, objectType, _a4) +// GenerateAssignments provides a mock function with given fields: ctx, tnt, objectID, objectType, _a4, initialConfigurations +func (_m *FormationAssignmentService) GenerateAssignments(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, _a4 *model.Formation, initialConfigurations model.InitialConfigurations) ([]*model.FormationAssignmentInput, error) { + ret := _m.Called(ctx, tnt, objectID, objectType, _a4, initialConfigurations) if len(ret) == 0 { panic("no return value specified for GenerateAssignments") @@ -95,19 +95,19 @@ func (_m *FormationAssignmentService) GenerateAssignments(ctx context.Context, t var r0 []*model.FormationAssignmentInput var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, *model.Formation) ([]*model.FormationAssignmentInput, error)); ok { - return rf(ctx, tnt, objectID, objectType, _a4) + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, *model.Formation, model.InitialConfigurations) ([]*model.FormationAssignmentInput, error)); ok { + return rf(ctx, tnt, objectID, objectType, _a4, initialConfigurations) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, *model.Formation) []*model.FormationAssignmentInput); ok { - r0 = rf(ctx, tnt, objectID, objectType, _a4) + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, *model.Formation, model.InitialConfigurations) []*model.FormationAssignmentInput); ok { + r0 = rf(ctx, tnt, objectID, objectType, _a4, initialConfigurations) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*model.FormationAssignmentInput) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, *model.Formation) error); ok { - r1 = rf(ctx, tnt, objectID, objectType, _a4) + if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, *model.Formation, model.InitialConfigurations) error); ok { + r1 = rf(ctx, tnt, objectID, objectType, _a4, initialConfigurations) } else { r1 = ret.Error(1) } diff --git a/components/director/internal/domain/formation/automock/service.go b/components/director/internal/domain/formation/automock/service.go index 806714f091..19e64e72fa 100644 --- a/components/director/internal/domain/formation/automock/service.go +++ b/components/director/internal/domain/formation/automock/service.go @@ -17,26 +17,29 @@ type Service struct { mock.Mock } -// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, _a4 -func (_m *Service) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, _a4 model.Formation) (*model.Formation, error) { - ret := _m.Called(ctx, tnt, objectID, objectType, _a4) +// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, _a4, initialConfigurations +func (_m *Service) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, _a4 model.Formation, initialConfigurations model.InitialConfigurations) (*model.Formation, error) { + ret := _m.Called(ctx, tnt, objectID, objectType, _a4, initialConfigurations) if len(ret) == 0 { panic("no return value specified for AssignFormation") } var r0 *model.Formation - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) *model.Formation); ok { - r0 = rf(ctx, tnt, objectID, objectType, _a4) + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) (*model.Formation, error)); ok { + return rf(ctx, tnt, objectID, objectType, _a4, initialConfigurations) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) *model.Formation); ok { + r0 = rf(ctx, tnt, objectID, objectType, _a4, initialConfigurations) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.Formation) } } - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) error); ok { - r1 = rf(ctx, tnt, objectID, objectType, _a4) + if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) error); ok { + r1 = rf(ctx, tnt, objectID, objectType, _a4, initialConfigurations) } else { r1 = ret.Error(1) } @@ -53,6 +56,10 @@ func (_m *Service) CreateFormation(ctx context.Context, tnt string, _a2 model.Fo } var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, model.Formation, string) (*model.Formation, error)); ok { + return rf(ctx, tnt, _a2, templateName) + } if rf, ok := ret.Get(0).(func(context.Context, string, model.Formation, string) *model.Formation); ok { r0 = rf(ctx, tnt, _a2, templateName) } else { @@ -61,7 +68,6 @@ func (_m *Service) CreateFormation(ctx context.Context, tnt string, _a2 model.Fo } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, model.Formation, string) error); ok { r1 = rf(ctx, tnt, _a2, templateName) } else { @@ -80,6 +86,10 @@ func (_m *Service) DeleteFormation(ctx context.Context, tnt string, _a2 model.Fo } var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, model.Formation) (*model.Formation, error)); ok { + return rf(ctx, tnt, _a2) + } if rf, ok := ret.Get(0).(func(context.Context, string, model.Formation) *model.Formation); ok { r0 = rf(ctx, tnt, _a2) } else { @@ -88,7 +98,6 @@ func (_m *Service) DeleteFormation(ctx context.Context, tnt string, _a2 model.Fo } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, model.Formation) error); ok { r1 = rf(ctx, tnt, _a2) } else { @@ -102,7 +111,15 @@ func (_m *Service) DeleteFormation(ctx context.Context, tnt string, _a2 model.Fo func (_m *Service) FinalizeDraftFormation(ctx context.Context, formationID string) (*model.Formation, error) { ret := _m.Called(ctx, formationID) + if len(ret) == 0 { + panic("no return value specified for FinalizeDraftFormation") + } + var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*model.Formation, error)); ok { + return rf(ctx, formationID) + } if rf, ok := ret.Get(0).(func(context.Context, string) *model.Formation); ok { r0 = rf(ctx, formationID) } else { @@ -111,7 +128,6 @@ func (_m *Service) FinalizeDraftFormation(ctx context.Context, formationID strin } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, formationID) } else { @@ -130,6 +146,10 @@ func (_m *Service) Get(ctx context.Context, id string) (*model.Formation, error) } var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*model.Formation, error)); ok { + return rf(ctx, id) + } if rf, ok := ret.Get(0).(func(context.Context, string) *model.Formation); ok { r0 = rf(ctx, id) } else { @@ -138,7 +158,6 @@ func (_m *Service) Get(ctx context.Context, id string) (*model.Formation, error) } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, id) } else { @@ -157,6 +176,10 @@ func (_m *Service) GetFormationByName(ctx context.Context, formationName string, } var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*model.Formation, error)); ok { + return rf(ctx, formationName, tnt) + } if rf, ok := ret.Get(0).(func(context.Context, string, string) *model.Formation); ok { r0 = rf(ctx, formationName, tnt) } else { @@ -165,7 +188,6 @@ func (_m *Service) GetFormationByName(ctx context.Context, formationName string, } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { r1 = rf(ctx, formationName, tnt) } else { @@ -179,7 +201,15 @@ func (_m *Service) GetFormationByName(ctx context.Context, formationName string, func (_m *Service) GetGlobalByID(ctx context.Context, id string) (*model.Formation, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for GetGlobalByID") + } + var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*model.Formation, error)); ok { + return rf(ctx, id) + } if rf, ok := ret.Get(0).(func(context.Context, string) *model.Formation); ok { r0 = rf(ctx, id) } else { @@ -188,7 +218,6 @@ func (_m *Service) GetGlobalByID(ctx context.Context, id string) (*model.Formati } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, id) } else { @@ -207,6 +236,10 @@ func (_m *Service) List(ctx context.Context, pageSize int, cursor string) (*mode } var r0 *model.FormationPage + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int, string) (*model.FormationPage, error)); ok { + return rf(ctx, pageSize, cursor) + } if rf, ok := ret.Get(0).(func(context.Context, int, string) *model.FormationPage); ok { r0 = rf(ctx, pageSize, cursor) } else { @@ -215,7 +248,6 @@ func (_m *Service) List(ctx context.Context, pageSize int, cursor string) (*mode } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, int, string) error); ok { r1 = rf(ctx, pageSize, cursor) } else { @@ -234,6 +266,10 @@ func (_m *Service) ListFormationsForObjectGlobal(ctx context.Context, objectID s } var r0 []*model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]*model.Formation, error)); ok { + return rf(ctx, objectID) + } if rf, ok := ret.Get(0).(func(context.Context, string) []*model.Formation); ok { r0 = rf(ctx, objectID) } else { @@ -242,7 +278,6 @@ func (_m *Service) ListFormationsForObjectGlobal(ctx context.Context, objectID s } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, objectID) } else { @@ -261,6 +296,10 @@ func (_m *Service) ResynchronizeFormationNotifications(ctx context.Context, form } var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, bool) (*model.Formation, error)); ok { + return rf(ctx, formationID, reset) + } if rf, ok := ret.Get(0).(func(context.Context, string, bool) *model.Formation); ok { r0 = rf(ctx, formationID, reset) } else { @@ -269,7 +308,6 @@ func (_m *Service) ResynchronizeFormationNotifications(ctx context.Context, form } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok { r1 = rf(ctx, formationID, reset) } else { @@ -288,6 +326,10 @@ func (_m *Service) UnassignFormation(ctx context.Context, tnt string, objectID s } var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, bool) (*model.Formation, error)); ok { + return rf(ctx, tnt, objectID, objectType, _a4, ignoreASA) + } if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, bool) *model.Formation); ok { r0 = rf(ctx, tnt, objectID, objectType, _a4, ignoreASA) } else { @@ -296,7 +338,6 @@ func (_m *Service) UnassignFormation(ctx context.Context, tnt string, objectID s } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, bool) error); ok { r1 = rf(ctx, tnt, objectID, objectType, _a4, ignoreASA) } else { @@ -306,13 +347,12 @@ func (_m *Service) UnassignFormation(ctx context.Context, tnt string, objectID s return r0, r1 } -type mockConstructorTestingTNewService interface { +// NewService creates a new instance of Service. 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 NewService(t interface { mock.TestingT Cleanup(func()) -} - -// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewService(t mockConstructorTestingTNewService) *Service { +}) *Service { mock := &Service{} mock.Mock.Test(t) diff --git a/components/director/internal/domain/formation/fixtures_test.go b/components/director/internal/domain/formation/fixtures_test.go index cdbc34a3bf..5bffed211b 100644 --- a/components/director/internal/domain/formation/fixtures_test.go +++ b/components/director/internal/domain/formation/fixtures_test.go @@ -56,6 +56,7 @@ const ( // Entity constants ApplicationID = "04f3568d-3e0c-4f6b-b646-e6979e9d060c" Application2ID = "6f5389cf-4f9e-46b3-9870-624d792d94ad" + Application3ID = "a05fc871-9d45-482e-9e9c-b89c91ad1381" ApplicationTemplateID = "58963c6f-24f6-4128-a05c-51d5356e7e09" ApplicationTemplate2ID = "88963c6f-24f6-4128-a05c-51d5356e7e09" RuntimeID = "rt-id" diff --git a/components/director/internal/domain/formation/resolver.go b/components/director/internal/domain/formation/resolver.go index 7a4cdd85eb..59fe131229 100644 --- a/components/director/internal/domain/formation/resolver.go +++ b/components/director/internal/domain/formation/resolver.go @@ -29,7 +29,7 @@ type Service interface { ListFormationsForObjectGlobal(ctx context.Context, objectID string) ([]*model.Formation, error) CreateFormation(ctx context.Context, tnt string, formation model.Formation, templateName string) (*model.Formation, error) DeleteFormation(ctx context.Context, tnt string, formation model.Formation) (*model.Formation, error) - AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) + AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, initialConfigurations model.InitialConfigurations) (*model.Formation, error) UnassignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, ignoreASA bool) (*model.Formation, error) ResynchronizeFormationNotifications(ctx context.Context, formationID string, reset bool) (*model.Formation, error) FinalizeDraftFormation(ctx context.Context, formationID string) (*model.Formation, error) @@ -55,7 +55,7 @@ type formationAssignmentService interface { ListAllForObjectGlobal(ctx context.Context, objectID string) ([]*model.FormationAssignment, error) ProcessFormationAssignments(ctx context.Context, formationAssignmentsForObject []*model.FormationAssignment, requests []*webhookclient.FormationAssignmentNotificationRequestTargetMapping, operation func(context.Context, *formationassignment.AssignmentMappingPairWithOperation) (bool, error), formationOperation model.FormationOperation) error ProcessFormationAssignmentPair(ctx context.Context, mappingPair *formationassignment.AssignmentMappingPairWithOperation) (bool, error) - GenerateAssignments(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation *model.Formation) ([]*model.FormationAssignmentInput, error) + GenerateAssignments(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation *model.Formation, initialConfigurations model.InitialConfigurations) ([]*model.FormationAssignmentInput, error) PersistAssignments(ctx context.Context, tnt string, assignments []*model.FormationAssignmentInput) ([]*model.FormationAssignment, error) CleanupFormationAssignment(ctx context.Context, mappingPair *formationassignment.AssignmentMappingPairWithOperation) (bool, error) GetAssignmentsForFormation(ctx context.Context, tenantID, formationID string) ([]*model.FormationAssignment, error) @@ -276,7 +276,7 @@ func (r *Resolver) DeleteFormation(ctx context.Context, formation graphql.Format } // AssignFormation assigns object to the provided formation -func (r *Resolver) AssignFormation(ctx context.Context, objectID string, objectType graphql.FormationObjectType, formation graphql.FormationInput) (*graphql.Formation, error) { +func (r *Resolver) AssignFormation(ctx context.Context, objectID string, objectType graphql.FormationObjectType, formation graphql.FormationInput, initialConfigurations []*graphql.InitialConfiguration) (*graphql.Formation, error) { tnt, err := tenant.LoadFromContext(ctx) if err != nil { return nil, err @@ -290,6 +290,42 @@ func (r *Resolver) AssignFormation(ctx context.Context, objectID string, objectT ctx = persistence.SaveToContext(ctx, tx) + formationFromDB, err := r.service.GetFormationByName(ctx, formation.Name, tnt) + if err != nil { + return nil, err + } + + assignmentsForFormation, err := r.formationAssignmentSvc.GetAssignmentsForFormation(ctx, tnt, formationFromDB.ID) + if err != nil { + return nil, err + } + + participants := make(map[string]struct{}, len(assignmentsForFormation)) + for _, assignment := range assignmentsForFormation { + participants[assignment.Source] = struct{}{} + participants[assignment.Target] = struct{}{} + } + + initCfgsSourceToTarget := make(model.InitialConfigurations) + for _, cfg := range initialConfigurations { + if cfg.SourceID != objectID && cfg.TargetID != objectID { + return nil, errors.Errorf("Initial Configuration does not contain assigned object %s as \"source\" or \"target\": %v", objectID, cfg) + } + + _, isSourceParticipant := participants[cfg.SourceID] + _, isTargetParticipant := participants[cfg.TargetID] + if (!isSourceParticipant && cfg.SourceID != objectID) || (!isTargetParticipant && cfg.TargetID != objectID) { + return nil, errors.Errorf("Initial Configurations contains non-participant \"source\" or \"target\": %v", cfg) + } + + if _, ok := initCfgsSourceToTarget[cfg.SourceID]; !ok { + initCfgsSourceToTarget[cfg.SourceID] = make(map[string]json.RawMessage) + } + + initialConfig := json.RawMessage(cfg.Configuration) + initCfgsSourceToTarget[cfg.SourceID][cfg.TargetID] = initialConfig + } + tenantMapping, err := r.tenantSvc.GetTenantByID(ctx, tnt) if err != nil { return nil, errors.Wrapf(err, "while getting parent tenant by internal ID %q...", tnt) @@ -302,7 +338,7 @@ func (r *Resolver) AssignFormation(ctx context.Context, objectID string, objectT } } - newFormation, err := r.service.AssignFormation(ctx, tnt, objectID, objectType, r.conv.FromGraphQL(formation)) + newFormation, err := r.service.AssignFormation(ctx, tnt, objectID, objectType, r.conv.FromGraphQL(formation), initCfgsSourceToTarget) if err != nil { return nil, err } diff --git a/components/director/internal/domain/formation/resolver_test.go b/components/director/internal/domain/formation/resolver_test.go index c414995500..a5618e6b41 100644 --- a/components/director/internal/domain/formation/resolver_test.go +++ b/components/director/internal/domain/formation/resolver_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "testing" dataloader "github.com/kyma-incubator/compass/components/director/internal/dataloaders" @@ -270,208 +271,439 @@ func TestAssignFormation(t *testing.T) { formationInput := graphql.FormationInput{ Name: testFormationName, } - tnt := "tenant" - externalTnt := "external-tenant" - tenantMapping := &model.BusinessTenantMapping{ExternalTenant: externalTnt} - testObjectType := graphql.FormationObjectTypeTenant - testErr := errors.New("test error") - txGen := txtest.NewTransactionContextGenerator(testErr) - - t.Run("successfully assigned formation", func(t *testing.T) { - // GIVEN - persist, transact := txGen.ThatSucceeds() - - mockService := &automock.Service{} - mockConverter := &automock.Converter{} - fetcherSvc := &automock.TenantFetcher{} - tenantSvc := &automock.TenantSvc{} - mockService.On("AssignFormation", contextThatHasTenant(tnt), tnt, "", testObjectType, modelFormation).Return(&modelFormation, nil) - - mockConverter.On("FromGraphQL", formationInput).Return(modelFormation) - mockConverter.On("ToGraphQL", &modelFormation).Return(&graphqlFormation, nil) - - fetcherSvc.On("FetchOnDemand", contextThatHasTenant(tnt), "", externalTnt).Return(nil) - - tenantSvc.On("GetTenantByID", contextThatHasTenant(tnt), tnt).Return(tenantMapping, nil).Once() - - ctx := tenant.SaveToContext(context.TODO(), tnt, externalTnt) - sut := formation.NewResolver(transact, mockService, mockConverter, nil, nil, fetcherSvc, tenantSvc) - - // WHEN - actual, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) - - // THEN - require.NoError(t, err) - assert.Equal(t, testFormationName, actual.Name) - mock.AssertExpectationsForObjects(t, persist, transact, mockService, mockConverter, fetcherSvc, tenantSvc) - }) - t.Run("returns error when can't get tenant by ID", func(t *testing.T) { - // GIVEN - persist, transact := txGen.ThatDoesntExpectCommit() - - mockService := &automock.Service{} - mockConverter := &automock.Converter{} - tenantSvc := &automock.TenantSvc{} - - ctx := tenant.SaveToContext(context.TODO(), tnt, externalTnt) - - tenantSvc.On("GetTenantByID", contextThatHasTenant(tnt), tnt).Return(nil, testErr).Once() - - sut := formation.NewResolver(transact, mockService, mockConverter, nil, nil, nil, tenantSvc) - - // WHEN - _, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) - - // THEN - require.Error(t, err) - assert.Contains(t, err.Error(), testErr.Error()) - mock.AssertExpectationsForObjects(t, persist, transact, mockService, mockConverter, tenantSvc) - }) - t.Run("returns error when objectType is tenant and cannot fetch its details", func(t *testing.T) { - // GIVEN - persist, transact := txGen.ThatDoesntExpectCommit() - - mockService := &automock.Service{} - mockConverter := &automock.Converter{} - fetcherSvc := &automock.TenantFetcher{} - tenantSvc := &automock.TenantSvc{} - - ctx := tenant.SaveToContext(context.TODO(), tnt, externalTnt) - fetcherSvc.On("FetchOnDemand", contextThatHasTenant(tnt), "", externalTnt).Return(testErr) - - tenantSvc.On("GetTenantByID", contextThatHasTenant(tnt), tnt).Return(tenantMapping, nil).Once() - - sut := formation.NewResolver(transact, mockService, mockConverter, nil, nil, fetcherSvc, tenantSvc) - - // WHEN - _, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) - - // THEN - require.Error(t, err) - assert.Contains(t, err.Error(), testErr.Error()) - mock.AssertExpectationsForObjects(t, persist, transact, mockService, mockConverter, fetcherSvc, tenantSvc) - }) - t.Run("returns error when can not load tenant from context", func(t *testing.T) { - // GIVEN - ctx := context.Background() - - sut := formation.NewResolver(nil, nil, nil, nil, nil, nil, nil) - - // WHEN - _, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) - - // THEN - require.Error(t, err) - assert.Contains(t, err.Error(), apperrors.NewCannotReadTenantError().Error()) - }) - t.Run("returns error when can not start db transaction", func(t *testing.T) { - // GIVEN - persist, transact := txGen.ThatFailsOnBegin() - ctx := tenant.SaveToContext(context.TODO(), tnt, externalTnt) - - sut := formation.NewResolver(transact, nil, nil, nil, nil, nil, nil) - - // WHEN - _, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) - - // THEN - require.Error(t, err) - assert.Contains(t, err.Error(), testErr.Error()) - mock.AssertExpectationsForObjects(t, persist, transact) - }) - t.Run("returns error when commit fails", func(t *testing.T) { - // GIVEN - persist, transact := txGen.ThatFailsOnCommit() - - mockService := &automock.Service{} - mockService.On("AssignFormation", contextThatHasTenant(tnt), tnt, "", testObjectType, modelFormation).Return(&modelFormation, nil) - - mockConverter := &automock.Converter{} - mockConverter.On("FromGraphQL", formationInput).Return(modelFormation) - - ctx := tenant.SaveToContext(context.TODO(), tnt, externalTnt) - - fetcherSvc := &automock.TenantFetcher{} - fetcherSvc.On("FetchOnDemand", contextThatHasTenant(tnt), "", externalTnt).Return(nil) - - tenantSvc := &automock.TenantSvc{} - tenantSvc.On("GetTenantByID", contextThatHasTenant(tnt), tnt).Return(tenantMapping, nil).Once() - - sut := formation.NewResolver(transact, mockService, mockConverter, nil, nil, fetcherSvc, tenantSvc) - - // WHEN - _, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) - - // THEN - require.Error(t, err) - assert.Contains(t, err.Error(), testErr.Error()) - mock.AssertExpectationsForObjects(t, persist, transact, mockService, mockConverter, fetcherSvc, tenantSvc) - }) - t.Run("returns error when assign formation fails", func(t *testing.T) { - // GIVEN - persist, transact := txGen.ThatDoesntExpectCommit() + ctxWithTenant := tenant.SaveToContext(context.TODO(), TntInternalID, TntExternalID) + tenantMapping := &model.BusinessTenantMapping{ExternalTenant: TntExternalID} + initialConfigurationsInput := []*graphql.InitialConfiguration{ + { + SourceID: Application3ID, + TargetID: ApplicationID, + Configuration: "{\"key\": \"value\"}", + }, + { + SourceID: Application2ID, + TargetID: Application3ID, + Configuration: "{\"key2\": \"value2\"}", + }, + } - mockService := &automock.Service{} - mockService.On("AssignFormation", contextThatHasTenant(tnt), tnt, "", testObjectType, modelFormation).Return(nil, testErr) + initialConfigurationsInputWithNonParticipant := []*graphql.InitialConfiguration{ + { + SourceID: Application3ID, + TargetID: "non-existing", + Configuration: "{\"key\": \"value\"}", + }, + } - mockConverter := &automock.Converter{} - mockConverter.On("FromGraphQL", formationInput).Return(modelFormation) + initialConfigurationsInputForOtherParticipantsOnly := []*graphql.InitialConfiguration{ + { + SourceID: ApplicationID, + TargetID: Application2ID, + Configuration: "{\"key\": \"value\"}", + }, + } - ctx := tenant.SaveToContext(context.TODO(), tnt, externalTnt) + initialConfigurations := make(model.InitialConfigurations, 2) + initialConfigurations[Application3ID] = make(map[string]json.RawMessage, 1) + initialConfigurations[Application2ID] = make(map[string]json.RawMessage, 1) + initialConfigurations[Application3ID][ApplicationID] = []byte("{\"key\": \"value\"}") + initialConfigurations[Application2ID][Application3ID] = []byte("{\"key2\": \"value2\"}") + formationAssignments := []*model.FormationAssignment{ + {ID: FormationAssignmentID, Source: ApplicationID, Target: ApplicationID, FormationID: FormationID}, + {ID: FormationAssignmentID2, Source: Application2ID, Target: ApplicationID, FormationID: FormationID}, + } + txGen := txtest.NewTransactionContextGenerator(testErr) - fetcherSvc := &automock.TenantFetcher{} - fetcherSvc.On("FetchOnDemand", contextThatHasTenant(tnt), "", externalTnt).Return(nil) + testCases := []struct { + Name string + TxFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) + ServiceFn func() *automock.Service + FormationAssignmentSvcFn func() *automock.FormationAssignmentService + ConverterFn func() *automock.Converter + TenantFetcherSvcFn func() *automock.TenantFetcher + TenantSvcFn func() *automock.TenantSvc + InputID string + ObjectType graphql.FormationObjectType + Context context.Context + InitialConfiguration []*graphql.InitialConfiguration + ExpectedFormation *graphql.Formation + ExpectedErrorMessage string + }{ + { + Name: "successfully assigned formation", + TxFn: txGen.ThatSucceeds, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + svc.On("AssignFormation", contextThatHasTenant(TntInternalID), TntInternalID, Application3ID, graphql.FormationObjectTypeApplication, modelFormation, initialConfigurations).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + ConverterFn: func() *automock.Converter { + converter := &automock.Converter{} + converter.On("FromGraphQL", formationInput).Return(modelFormation).Once() + converter.On("ToGraphQL", &modelFormation).Return(&graphqlFormation, nil).Once() + return converter + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(tenantMapping, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + ExpectedFormation: &graphqlFormation, + Context: ctxWithTenant, + }, + { + Name: "successfully assigned formation with ObjectType tenant", + TxFn: txGen.ThatSucceeds, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + svc.On("AssignFormation", contextThatHasTenant(TntInternalID), TntInternalID, Application3ID, graphql.FormationObjectTypeTenant, modelFormation, model.InitialConfigurations{}).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + ConverterFn: func() *automock.Converter { + converter := &automock.Converter{} + converter.On("FromGraphQL", formationInput).Return(modelFormation).Once() + converter.On("ToGraphQL", &modelFormation).Return(&graphqlFormation, nil).Once() + return converter + }, + TenantFetcherSvcFn: func() *automock.TenantFetcher { + svc := &automock.TenantFetcher{} + svc.On("FetchOnDemand", contextThatHasTenant(TntInternalID), Application3ID, TntExternalID).Return(nil).Once() + return svc + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(tenantMapping, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeTenant, + InitialConfiguration: nil, + ExpectedFormation: &graphqlFormation, + Context: ctxWithTenant, + }, + { + Name: "error when fails to convert formation result to graphql", + TxFn: txGen.ThatSucceeds, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + svc.On("AssignFormation", contextThatHasTenant(TntInternalID), TntInternalID, Application3ID, graphql.FormationObjectTypeApplication, modelFormation, initialConfigurations).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + ConverterFn: func() *automock.Converter { + converter := &automock.Converter{} + converter.On("FromGraphQL", formationInput).Return(modelFormation).Once() + converter.On("ToGraphQL", &modelFormation).Return(nil, testErr).Once() + return converter + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(tenantMapping, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: testErr.Error(), + }, + { + Name: "error when transaction commit failed", + TxFn: txGen.ThatFailsOnCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + svc.On("AssignFormation", contextThatHasTenant(TntInternalID), TntInternalID, Application3ID, graphql.FormationObjectTypeApplication, modelFormation, initialConfigurations).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + ConverterFn: func() *automock.Converter { + converter := &automock.Converter{} + converter.On("FromGraphQL", formationInput).Return(modelFormation).Once() + return converter + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(tenantMapping, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: "while committing transaction", + }, + { + Name: "error when assign to formation fails", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + svc.On("AssignFormation", contextThatHasTenant(TntInternalID), TntInternalID, Application3ID, graphql.FormationObjectTypeApplication, modelFormation, initialConfigurations).Return(nil, testErr).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + ConverterFn: func() *automock.Converter { + converter := &automock.Converter{} + converter.On("FromGraphQL", formationInput).Return(modelFormation).Once() + return converter + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(tenantMapping, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: testErr.Error(), + }, + { + Name: "error when fetching tenant fails", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + TenantFetcherSvcFn: func() *automock.TenantFetcher { + svc := &automock.TenantFetcher{} + svc.On("FetchOnDemand", contextThatHasTenant(TntInternalID), Application3ID, TntExternalID).Return(testErr).Once() + return svc + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(tenantMapping, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeTenant, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: "while trying to create if not exists subaccount", + }, + { + Name: "error when getting tenant by ID fails", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + TenantSvcFn: func() *automock.TenantSvc { + svc := &automock.TenantSvc{} + svc.On("GetTenantByID", contextThatHasTenant(TntInternalID), TntInternalID).Return(nil, testErr).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: "while getting parent tenant by internal ID", + }, + { + Name: "error when initial configuration contains non-participant object as source or target", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInputWithNonParticipant, + Context: ctxWithTenant, + ExpectedErrorMessage: "Initial Configurations contains non-participant \"source\" or \"target\":", + }, + { + Name: "error when provided initial configuration does not contain assigned object as source or target", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(formationAssignments, nil).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInputForOtherParticipantsOnly, + Context: ctxWithTenant, + ExpectedErrorMessage: fmt.Sprintf("Initial Configuration does not contain assigned object %s as \"source\" or \"target\"", Application3ID), + }, + { + Name: "error when getting formation assignments fails", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(&modelFormation, nil).Once() + return svc + }, + FormationAssignmentSvcFn: func() *automock.FormationAssignmentService { + svc := &automock.FormationAssignmentService{} + svc.On("GetAssignmentsForFormation", contextThatHasTenant(TntInternalID), TntInternalID, FormationID).Return(nil, testErr).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: testErr.Error(), + }, + { + Name: "error when getting formation by name fails", + TxFn: txGen.ThatDoesntExpectCommit, + ServiceFn: func() *automock.Service { + svc := &automock.Service{} + svc.On("GetFormationByName", contextThatHasTenant(TntInternalID), testFormationName, TntInternalID).Return(nil, testErr).Once() + return svc + }, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: testErr.Error(), + }, + { + Name: "error when transaction begin fails", + TxFn: txGen.ThatFailsOnBegin, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: ctxWithTenant, + ExpectedErrorMessage: testErr.Error(), + }, + { + Name: "error when context does not contain tenant", + TxFn: txGen.ThatFailsOnBegin, + InputID: Application3ID, + ObjectType: graphql.FormationObjectTypeApplication, + InitialConfiguration: initialConfigurationsInput, + Context: context.TODO(), + ExpectedErrorMessage: "cannot read tenant from context", + }, + } + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + // GIVEN + persist, transact := testCase.TxFn() + service := &automock.Service{} + if testCase.ServiceFn != nil { + service = testCase.ServiceFn() + } + formationAssignmentSvc := &automock.FormationAssignmentService{} + if testCase.FormationAssignmentSvcFn != nil { + formationAssignmentSvc = testCase.FormationAssignmentSvcFn() + } + converter := &automock.Converter{} + if testCase.ConverterFn != nil { + converter = testCase.ConverterFn() + } + tenantFetcher := &automock.TenantFetcher{} + if testCase.TenantFetcherSvcFn != nil { + tenantFetcher = testCase.TenantFetcherSvcFn() + } + tenantService := &automock.TenantSvc{} + if testCase.TenantSvcFn != nil { + tenantService = testCase.TenantSvcFn() + } - tenantSvc := &automock.TenantSvc{} - tenantSvc.On("GetTenantByID", contextThatHasTenant(tnt), tnt).Return(tenantMapping, nil).Once() + resolver := formation.NewResolver(transact, service, converter, formationAssignmentSvc, nil, tenantFetcher, tenantService) - sut := formation.NewResolver(transact, mockService, mockConverter, nil, nil, fetcherSvc, tenantSvc) + // WHEN + formationResult, err := resolver.AssignFormation(testCase.Context, testCase.InputID, testCase.ObjectType, formationInput, testCase.InitialConfiguration) - // WHEN - actual, err := sut.AssignFormation(ctx, "", testObjectType, formationInput) + // THEN + if testCase.ExpectedErrorMessage != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), testCase.ExpectedErrorMessage) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.ExpectedFormation, formationResult) + } - // THEN - require.Error(t, err) - assert.Contains(t, err.Error(), testErr.Error()) - require.Nil(t, actual) - mock.AssertExpectationsForObjects(t, persist, transact, mockService, mockConverter, fetcherSvc, tenantSvc) - }) + mock.AssertExpectationsForObjects(t, persist, service, formationAssignmentSvc, converter, tenantFetcher, tenantService) + }) + } } func TestUnassignFormation(t *testing.T) { formationInput := graphql.FormationInput{ Name: testFormationName, } - tnt := "tenant" - externalTnt := "external-tenant" - testErr := errors.New("test error") + ctxWithTenant := tenant.SaveToContext(context.TODO(), TntInternalID, TntExternalID) txGen := txtest.NewTransactionContextGenerator(testErr) testCases := []struct { - Name string - TxFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) - ServiceFn func() *automock.Service - ConverterFn func() *automock.Converter - FormationAssignmentSvcFn func() *automock.FormationAssignmentService - InputID string - ObjectType graphql.FormationObjectType - Context context.Context - ExpectedFormation *graphql.Formation - ExpectedError error + Name string + TxFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) + ServiceFn func() *automock.Service + ConverterFn func() *automock.Converter + InputID string + ObjectType graphql.FormationObjectType + Context context.Context + ExpectedFormation *graphql.Formation + ExpectedError error }{ { Name: "successfully unassigned formation", TxFn: txGen.ThatSucceeds, ConverterFn: func() *automock.Converter { conv := &automock.Converter{} - conv.On("FromGraphQL", formationInput).Return(modelFormation) - conv.On("ToGraphQL", &modelFormation).Return(&graphqlFormation, nil) + conv.On("FromGraphQL", formationInput).Return(modelFormation).Once() + conv.On("ToGraphQL", &modelFormation).Return(&graphqlFormation, nil).Once() return conv }, - Context: tenant.SaveToContext(context.TODO(), tnt, externalTnt), + Context: ctxWithTenant, ObjectType: graphql.FormationObjectTypeTenant, ServiceFn: func() *automock.Service { svc := &automock.Service{} - svc.On("UnassignFormation", contextThatHasTenant(tnt), tnt, "", graphql.FormationObjectTypeTenant, modelFormation, false).Return(&modelFormation, nil) + svc.On("UnassignFormation", contextThatHasTenant(TntInternalID), TntInternalID, "", graphql.FormationObjectTypeTenant, modelFormation, false).Return(&modelFormation, nil).Once() return svc }, ExpectedFormation: &graphqlFormation, @@ -479,10 +711,8 @@ func TestUnassignFormation(t *testing.T) { { Name: "fails when transaction fails to open", TxFn: txGen.ThatFailsOnBegin, - ConverterFn: unusedConverter, - Context: tenant.SaveToContext(context.TODO(), tnt, externalTnt), + Context: ctxWithTenant, ObjectType: graphql.FormationObjectTypeApplication, - ServiceFn: unusedService, InputID: ApplicationID, ExpectedError: testErr, }, @@ -491,46 +721,42 @@ func TestUnassignFormation(t *testing.T) { TxFn: txGen.ThatDoesntExpectCommit, Context: context.TODO(), ObjectType: graphql.FormationObjectTypeTenant, - ConverterFn: unusedConverter, - ServiceFn: unusedService, ExpectedError: apperrors.NewCannotReadTenantError(), }, { Name: "returns error when can not start db transaction", TxFn: txGen.ThatFailsOnBegin, - Context: tenant.SaveToContext(context.TODO(), tnt, externalTnt), + Context: ctxWithTenant, ObjectType: graphql.FormationObjectTypeTenant, - ConverterFn: unusedConverter, - ServiceFn: unusedService, ExpectedError: testErr, }, { Name: "returns error when commit fails", TxFn: txGen.ThatFailsOnCommit, - Context: tenant.SaveToContext(context.TODO(), tnt, externalTnt), + Context: ctxWithTenant, ObjectType: graphql.FormationObjectTypeTenant, ConverterFn: func() *automock.Converter { conv := &automock.Converter{} - conv.On("FromGraphQL", formationInput).Return(modelFormation) + conv.On("FromGraphQL", formationInput).Return(modelFormation).Once() return conv }, ServiceFn: func() *automock.Service { svc := &automock.Service{} - svc.On("UnassignFormation", contextThatHasTenant(tnt), tnt, "", graphql.FormationObjectTypeTenant, modelFormation, false).Return(&modelFormation, nil) + svc.On("UnassignFormation", contextThatHasTenant(TntInternalID), TntInternalID, "", graphql.FormationObjectTypeTenant, modelFormation, false).Return(&modelFormation, nil).Once() return svc }, ExpectedError: testErr, }, { Name: "returns error when assign formation fails", TxFn: txGen.ThatDoesntExpectCommit, - Context: tenant.SaveToContext(context.TODO(), tnt, externalTnt), + Context: ctxWithTenant, ObjectType: graphql.FormationObjectTypeTenant, ConverterFn: func() *automock.Converter { conv := &automock.Converter{} - conv.On("FromGraphQL", formationInput).Return(modelFormation) + conv.On("FromGraphQL", formationInput).Return(modelFormation).Once() return conv }, ServiceFn: func() *automock.Service { svc := &automock.Service{} - svc.On("UnassignFormation", contextThatHasTenant(tnt), tnt, "", graphql.FormationObjectTypeTenant, modelFormation, false).Return(nil, testErr) + svc.On("UnassignFormation", contextThatHasTenant(TntInternalID), TntInternalID, "", graphql.FormationObjectTypeTenant, modelFormation, false).Return(nil, testErr).Once() return svc }, ExpectedError: testErr, @@ -540,14 +766,16 @@ func TestUnassignFormation(t *testing.T) { t.Run(testCase.Name, func(t *testing.T) { // GIVEN persist, transact := testCase.TxFn() - service := testCase.ServiceFn() - converter := testCase.ConverterFn() - formationAssignmentSvc := &automock.FormationAssignmentService{} - if testCase.FormationAssignmentSvcFn != nil { - formationAssignmentSvc = testCase.FormationAssignmentSvcFn() + service := &automock.Service{} + if testCase.ServiceFn != nil { + service = testCase.ServiceFn() + } + converter := &automock.Converter{} + if testCase.ConverterFn != nil { + converter = testCase.ConverterFn() } - resolver := formation.NewResolver(transact, service, converter, formationAssignmentSvc, nil, nil, nil) + resolver := formation.NewResolver(transact, service, converter, nil, nil, nil, nil) // WHEN f, err := resolver.UnassignFormation(testCase.Context, testCase.InputID, testCase.ObjectType, formationInput) @@ -561,22 +789,20 @@ func TestUnassignFormation(t *testing.T) { } assert.Equal(t, testCase.ExpectedFormation, f) - mock.AssertExpectationsForObjects(t, persist, service, converter, formationAssignmentSvc) + mock.AssertExpectationsForObjects(t, persist, service, converter) }) } } func TestUnassignFormationGlobal(t *testing.T) { - testErr := errors.New("test error") txGen := txtest.NewTransactionContextGenerator(testErr) testCases := []struct { - Name string - TxFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) - ServiceFn func() *automock.Service - ConverterFn func() *automock.Converter - FormationAssignmentSvcFn func() *automock.FormationAssignmentService - ExpectedFormation *graphql.Formation - ExpectedError error + Name string + TxFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) + ServiceFn func() *automock.Service + ConverterFn func() *automock.Converter + ExpectedFormation *graphql.Formation + ExpectedError error }{ { Name: "successfully unassigned formation", @@ -597,20 +823,15 @@ func TestUnassignFormationGlobal(t *testing.T) { { Name: "fails when transaction fails to open", TxFn: txGen.ThatFailsOnBegin, - ConverterFn: unusedConverter, - ServiceFn: unusedService, ExpectedError: testErr, }, { Name: "returns error when can not start db transaction", TxFn: txGen.ThatFailsOnBegin, - ConverterFn: unusedConverter, - ServiceFn: unusedService, ExpectedError: testErr, }, { - Name: "returns error when commit fails", - TxFn: txGen.ThatFailsOnCommit, - ConverterFn: unusedConverter, + Name: "returns error when commit fails", + TxFn: txGen.ThatFailsOnCommit, ServiceFn: func() *automock.Service { svc := &automock.Service{} svc.On("GetGlobalByID", mock.Anything, FormationID).Return(&modelFormationWithTenant, nil) @@ -620,9 +841,8 @@ func TestUnassignFormationGlobal(t *testing.T) { ExpectedError: testErr, }, { - Name: "returns error when unassign formation fails", - TxFn: txGen.ThatDoesntExpectCommit, - ConverterFn: unusedConverter, + Name: "returns error when unassign formation fails", + TxFn: txGen.ThatDoesntExpectCommit, ServiceFn: func() *automock.Service { svc := &automock.Service{} svc.On("GetGlobalByID", mock.Anything, FormationID).Return(&modelFormationWithTenant, nil) @@ -632,9 +852,8 @@ func TestUnassignFormationGlobal(t *testing.T) { ExpectedError: testErr, }, { - Name: "returns error when get formation fails", - TxFn: txGen.ThatDoesntExpectCommit, - ConverterFn: unusedConverter, + Name: "returns error when get formation fails", + TxFn: txGen.ThatDoesntExpectCommit, ServiceFn: func() *automock.Service { svc := &automock.Service{} svc.On("GetGlobalByID", mock.Anything, FormationID).Return(nil, testErr) @@ -647,14 +866,16 @@ func TestUnassignFormationGlobal(t *testing.T) { t.Run(testCase.Name, func(t *testing.T) { // GIVEN persist, transact := testCase.TxFn() - service := testCase.ServiceFn() - converter := testCase.ConverterFn() - formationAssignmentSvc := &automock.FormationAssignmentService{} - if testCase.FormationAssignmentSvcFn != nil { - formationAssignmentSvc = testCase.FormationAssignmentSvcFn() + service := &automock.Service{} + if testCase.ServiceFn != nil { + service = testCase.ServiceFn() + } + converter := &automock.Converter{} + if testCase.ConverterFn != nil { + converter = testCase.ConverterFn() } - resolver := formation.NewResolver(transact, service, converter, formationAssignmentSvc, nil, nil, nil) + resolver := formation.NewResolver(transact, service, converter, nil, nil, nil, nil) // WHEN f, err := resolver.UnassignFormationGlobal(emptyCtx, ApplicationID, graphql.FormationObjectTypeApplication, FormationID) @@ -668,7 +889,7 @@ func TestUnassignFormationGlobal(t *testing.T) { } assert.Equal(t, testCase.ExpectedFormation, f) - mock.AssertExpectationsForObjects(t, persist, service, converter, formationAssignmentSvc) + mock.AssertExpectationsForObjects(t, persist, service, converter) }) } } diff --git a/components/director/internal/domain/formation/service.go b/components/director/internal/domain/formation/service.go index e927a12e9a..aab3901ea4 100644 --- a/components/director/internal/domain/formation/service.go +++ b/components/director/internal/domain/formation/service.go @@ -567,7 +567,7 @@ func (s *service) DeleteFormationEntityAndScenarios(ctx context.Context, tnt, fo // // If the graphql.FormationObjectType is graphql.FormationObjectTypeTenant it will // create automatic scenario assignment with the caller and target tenant which then will assign the right Runtime / RuntimeContexts based on the formation template's runtimeType. -func (s *service) AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (f *model.Formation, err error) { +func (s *service) AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, initialConfigurations model.InitialConfigurations) (f *model.Formation, err error) { log.C(ctx).Infof("Assigning object with ID %q of type %q to formation %q", objectID, objectType, formation.Name) ft, err := s.getFormationWithTemplate(ctx, formation.Name, tnt) @@ -609,7 +609,7 @@ func (s *service) AssignFormation(ctx context.Context, tnt, objectID string, obj // If 'err' is used for the name of the returned error, a new variable that shadows the 'err' variable from the outer scope // is created. As the defer statement is declared in the scope of the case fragment of the switch it will be bound to the 'err' variable in the same scope // which is the new one. Then the deffer will not execute its logic in case of error in the outer scope. - assignmentInputs, terr := s.formationAssignmentService.GenerateAssignments(ctx, tnt, objectID, objectType, formationFromDB) + assignmentInputs, terr := s.formationAssignmentService.GenerateAssignments(ctx, tnt, objectID, objectType, formationFromDB, initialConfigurations) if terr != nil { return nil, terr } @@ -1588,7 +1588,11 @@ func (s *service) CreateAutomaticScenarioAssignment(ctx context.Context, in *mod return nil, errors.Wrap(err, "while persisting Assignment") } - if err = s.asaEngine.EnsureScenarioAssigned(ctx, in, s.AssignFormation); err != nil { + assignScenarioFunc := func(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) { + return s.AssignFormation(ctx, tnt, objectID, objectType, formation, nil) + } + + if err = s.asaEngine.EnsureScenarioAssigned(ctx, in, assignScenarioFunc); err != nil { return nil, errors.Wrap(err, "while assigning scenario to runtimes matching selector") } diff --git a/components/director/internal/domain/formationassignment/fixtures_test.go b/components/director/internal/domain/formationassignment/fixtures_test.go index c019339f86..f90812159e 100644 --- a/components/director/internal/domain/formationassignment/fixtures_test.go +++ b/components/director/internal/domain/formationassignment/fixtures_test.go @@ -526,8 +526,8 @@ func fixFormationAssignmentsWithObjectTypeAndID(objectType model.FormationAssign } } -func fixFormationAssignmentInputsWithObjectTypeAndID(objectType model.FormationAssignmentType, objectID, appID, rtmID, rtmCtxID string) []*model.FormationAssignmentInput { - return []*model.FormationAssignmentInput{ +func fixFormationAssignmentInputsWithObjectTypeAndID(objectType model.FormationAssignmentType, objectID, appID, rtmID, rtmCtxID string, configurations model.InitialConfigurations) []*model.FormationAssignmentInput { + assignments := []*model.FormationAssignmentInput{ { FormationID: "ID", Source: objectID, @@ -600,6 +600,14 @@ func fixFormationAssignmentInputsWithObjectTypeAndID(objectType model.FormationA Error: nil, }, } + + for i, assignment := range assignments { + if val, ok := configurations[assignment.Source]; ok { + assignments[i].Value = val[assignment.Target] + } + } + + return assignments } func fixFormationAssignmentsForSelf(appID, rtmID, rtmCtxID string) []*model.FormationAssignment { diff --git a/components/director/internal/domain/formationassignment/service.go b/components/director/internal/domain/formationassignment/service.go index 3f427cc90e..71cf679caa 100644 --- a/components/director/internal/domain/formationassignment/service.go +++ b/components/director/internal/domain/formationassignment/service.go @@ -428,7 +428,7 @@ func (s *service) Exists(ctx context.Context, id string) (bool, error) { // For the second assignment the source and target are swapped. // // In case of objectType==RUNTIME_CONTEXT formationAssignments for the object and it's parent runtime are not generated. -func (s *service) GenerateAssignments(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation *model.Formation) ([]*model.FormationAssignmentInput, error) { +func (s *service) GenerateAssignments(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation *model.Formation, initialConfigurations model.InitialConfigurations) ([]*model.FormationAssignmentInput, error) { applications, err := s.applicationRepository.ListByScenariosNoPaging(ctx, tnt, []string{formation.Name}) if err != nil { return nil, err @@ -487,7 +487,7 @@ func (s *service) GenerateAssignments(ctx context.Context, tnt, objectID string, if !isAssigned || appID == objectID { continue } - assignments = append(assignments, s.GenerateAssignmentsForParticipant(objectID, objectType, formation, model.FormationAssignmentTypeApplication, appID)...) + assignments = append(assignments, s.GenerateAssignmentsForParticipant(objectID, objectType, formation, model.FormationAssignmentTypeApplication, appID, initialConfigurations)...) } // When runtime context is assigned to formation its parent runtime is unassigned from the formation. @@ -507,14 +507,14 @@ func (s *service) GenerateAssignments(ctx context.Context, tnt, objectID string, if !isAssigned || runtimeID == objectID || runtimeID == parentID { continue } - assignments = append(assignments, s.GenerateAssignmentsForParticipant(objectID, objectType, formation, model.FormationAssignmentTypeRuntime, runtimeID)...) + assignments = append(assignments, s.GenerateAssignmentsForParticipant(objectID, objectType, formation, model.FormationAssignmentTypeRuntime, runtimeID, initialConfigurations)...) } for runtimeCtxID, isAssigned := range rtCtxIDs { if !isAssigned || runtimeCtxID == objectID { continue } - assignments = append(assignments, s.GenerateAssignmentsForParticipant(objectID, objectType, formation, model.FormationAssignmentTypeRuntimeContext, runtimeCtxID)...) + assignments = append(assignments, s.GenerateAssignmentsForParticipant(objectID, objectType, formation, model.FormationAssignmentTypeRuntimeContext, runtimeCtxID, initialConfigurations)...) } assignments = append(assignments, &model.FormationAssignmentInput{ @@ -524,7 +524,7 @@ func (s *service) GenerateAssignments(ctx context.Context, tnt, objectID string, Target: objectID, TargetType: model.FormationAssignmentType(objectType), State: string(model.InitialFormationState), - Value: nil, + Value: getInitialConfiguration(objectID, objectID, initialConfigurations), Error: nil, }) @@ -551,7 +551,7 @@ func (s *service) PersistAssignments(ctx context.Context, tnt string, assignment } // GenerateAssignmentsForParticipant creates in-memory the assignments for two participants in the initial state -func (s *service) GenerateAssignmentsForParticipant(objectID string, objectType graphql.FormationObjectType, formation *model.Formation, participantType model.FormationAssignmentType, participantID string) []*model.FormationAssignmentInput { +func (s *service) GenerateAssignmentsForParticipant(objectID string, objectType graphql.FormationObjectType, formation *model.Formation, participantType model.FormationAssignmentType, participantID string, initialConfigurations model.InitialConfigurations) []*model.FormationAssignmentInput { assignments := make([]*model.FormationAssignmentInput, 0, 2) assignments = append(assignments, &model.FormationAssignmentInput{ FormationID: formation.ID, @@ -560,7 +560,7 @@ func (s *service) GenerateAssignmentsForParticipant(objectID string, objectType Target: participantID, TargetType: participantType, State: string(model.InitialAssignmentState), - Value: nil, + Value: getInitialConfiguration(objectID, participantID, initialConfigurations), Error: nil, }) assignments = append(assignments, &model.FormationAssignmentInput{ @@ -570,7 +570,7 @@ func (s *service) GenerateAssignmentsForParticipant(objectID string, objectType Target: objectID, TargetType: model.FormationAssignmentType(objectType), State: string(model.InitialAssignmentState), - Value: nil, + Value: getInitialConfiguration(participantID, objectID, initialConfigurations), Error: nil, }) return assignments @@ -1203,3 +1203,12 @@ func isConfigNotEmpty(config *string) bool { func isErrorNotEmpty(responseError *string) bool { return responseError != nil && *responseError != "" } + +func getInitialConfiguration(src, tgt string, initialConfigurations model.InitialConfigurations) json.RawMessage { + if targetToCfg, ok := initialConfigurations[src]; ok { + if config, ok := targetToCfg[tgt]; ok { + return config + } + } + return nil +} diff --git a/components/director/internal/domain/formationassignment/service_test.go b/components/director/internal/domain/formationassignment/service_test.go index 0e55c49451..2122ed22f0 100644 --- a/components/director/internal/domain/formationassignment/service_test.go +++ b/components/director/internal/domain/formationassignment/service_test.go @@ -1336,9 +1336,14 @@ func TestService_GenerateAssignments(t *testing.T) { allAssignments := append(append(formationAssignmentsForApplication, append(formationAssignmentsForRuntime, append(formationAssignmentsForRuntimeContext, formationAssignmentsForRuntimeContextWithParentInTheFormation...)...)...), formationAssignmentsForSelf...) - formationAssignmentInputsForApplication := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeApplication, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID) - formationAssignmentInputsForRuntime := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeRuntime, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID) - formationAssignmentInputsForRuntimeContext := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeRuntimeContext, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID) + initialConfigurations := make(model.InitialConfigurations, 2) + initialConfigurations[objectID] = make(map[string]json.RawMessage, 1) + initialConfigurations[applications[0].ID] = make(map[string]json.RawMessage, 1) + initialConfigurations[applications[0].ID][objectID] = []byte("{\"key\": \"value\"}") + initialConfigurations[objectID][runtimes[0].ID] = []byte("{\"key2\": \"value2\"}") + formationAssignmentInputsForApplication := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeApplication, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID, initialConfigurations) + formationAssignmentInputsForRuntime := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeRuntime, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID, initialConfigurations) + formationAssignmentInputsForRuntimeContext := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeRuntimeContext, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID, initialConfigurations) formationAssignmentInputsForRuntimeContextWithParentInTheFormation := fixFormationAssignmentInputsForRtmCtxWithAppAndRtmCtx(model.FormationAssignmentTypeRuntimeContext, objectID, applications[0].ID, runtimeContexts[0].ID) formationAssignmentIDs := []string{"ID1", "ID2", "ID3", "ID4", "ID5", "ID6", "ID7"} @@ -1357,6 +1362,7 @@ func TestService_GenerateAssignments(t *testing.T) { RuntimeRepo func() *automock.RuntimeRepository RuntimeContextRepo func() *automock.RuntimeContextRepository UIDService func() *automock.UIDService + InitialConfigurations model.InitialConfigurations ExpectedOutput []*model.FormationAssignmentInput ExpectedErrorMsg string }{ @@ -1391,7 +1397,8 @@ func TestService_GenerateAssignments(t *testing.T) { repo.On("ListByScenarios", ctxWithTenant, TestTenantID, []string{formation.Name}).Return(runtimeContexts, nil).Once() return repo }, - ExpectedOutput: formationAssignmentInputsForApplication, + InitialConfigurations: initialConfigurations, + ExpectedOutput: formationAssignmentInputsForApplication, }, { Name: "Success does not create formation assignment for entity that is being unassigned asynchronously", @@ -1425,7 +1432,8 @@ func TestService_GenerateAssignments(t *testing.T) { repo.On("ListByScenarios", ctxWithTenant, TestTenantID, []string{formation.Name}).Return(runtimeContexts, nil).Once() return repo }, - ExpectedOutput: formationAssignmentInputsForApplication, + InitialConfigurations: initialConfigurations, + ExpectedOutput: formationAssignmentInputsForApplication, }, { Name: "Success does not create formation assignment for application and itself", @@ -1458,7 +1466,8 @@ func TestService_GenerateAssignments(t *testing.T) { repo.On("ListByScenarios", ctxWithTenant, TestTenantID, []string{formation.Name}).Return(runtimeContexts, nil).Once() return repo }, - ExpectedOutput: formationAssignmentInputsForApplication, + InitialConfigurations: initialConfigurations, + ExpectedOutput: formationAssignmentInputsForApplication, }, { Name: "Success does not create formation assignment for runtime and itself", @@ -1491,7 +1500,8 @@ func TestService_GenerateAssignments(t *testing.T) { repo.On("ListByScenarios", ctxWithTenant, TestTenantID, []string{formation.Name}).Return(runtimeContexts, nil).Once() return repo }, - ExpectedOutput: formationAssignmentInputsForRuntime, + InitialConfigurations: initialConfigurations, + ExpectedOutput: formationAssignmentInputsForRuntime, }, { Name: "Success does not create formation assignment for runtime context and itself", @@ -1525,7 +1535,8 @@ func TestService_GenerateAssignments(t *testing.T) { repo.On("GetByID", ctxWithTenant, TestTenantID, objectID).Return(&model.RuntimeContext{RuntimeID: "random"}, nil) return repo }, - ExpectedOutput: formationAssignmentInputsForRuntimeContext, + InitialConfigurations: initialConfigurations, + ExpectedOutput: formationAssignmentInputsForRuntimeContext, }, { Name: "Success does not create formation assignment for runtime context and it's parent runtime", @@ -1691,7 +1702,7 @@ func TestService_GenerateAssignments(t *testing.T) { svc := formationassignment.NewService(formationAssignmentRepo, uidSvc, appRepo, runtimeRepo, runtimeContextRepo, nil, nil, nil, nil, nil, nil, "", "") // WHEN - r, err := svc.GenerateAssignments(testCase.Context, TestTenantID, objectID, testCase.ObjectType, formation) + r, err := svc.GenerateAssignments(testCase.Context, TestTenantID, objectID, testCase.ObjectType, formation, testCase.InitialConfigurations) if testCase.ExpectedErrorMsg != "" { require.Error(t, err) @@ -1716,7 +1727,7 @@ func TestService_PersistAssignments(t *testing.T) { runtimeContexts := []*model.RuntimeContext{{ID: "runtimeContext"}} formationAssignments := fixFormationAssignmentsWithObjectTypeAndID(model.FormationAssignmentTypeApplication, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID) - formationAssignmentInputs := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeApplication, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID) + formationAssignmentInputs := fixFormationAssignmentInputsWithObjectTypeAndID(model.FormationAssignmentTypeApplication, objectID, applications[0].ID, runtimes[0].ID, runtimeContexts[0].ID, nil) formationAssignmentIDs := []string{"ID1", "ID2", "ID3", "ID4", "ID5", "ID6", "ID7"} testCases := []struct { diff --git a/components/director/internal/domain/root_resolver.go b/components/director/internal/domain/root_resolver.go index f46a147ebb..0b54a9d81d 100644 --- a/components/director/internal/domain/root_resolver.go +++ b/components/director/internal/domain/root_resolver.go @@ -790,8 +790,8 @@ func (r *mutationResolver) UpdateFormationTemplate(ctx context.Context, id strin return r.formationTemplate.UpdateFormationTemplate(ctx, id, in) } -func (r *mutationResolver) AssignFormation(ctx context.Context, objectID string, objectType graphql.FormationObjectType, formation graphql.FormationInput) (*graphql.Formation, error) { - return r.formation.AssignFormation(ctx, objectID, objectType, formation) +func (r *mutationResolver) AssignFormation(ctx context.Context, objectID string, objectType graphql.FormationObjectType, formation graphql.FormationInput, initialConfigurations []*graphql.InitialConfiguration) (*graphql.Formation, error) { + return r.formation.AssignFormation(ctx, objectID, objectType, formation, initialConfigurations) } func (r *mutationResolver) UnassignFormation(ctx context.Context, objectID string, objectType graphql.FormationObjectType, formation graphql.FormationInput) (*graphql.Formation, error) { diff --git a/components/director/internal/domain/runtime/automock/formation_service.go b/components/director/internal/domain/runtime/automock/formation_service.go index c7f017d6b7..f18ad72053 100644 --- a/components/director/internal/domain/runtime/automock/formation_service.go +++ b/components/director/internal/domain/runtime/automock/formation_service.go @@ -16,9 +16,9 @@ type FormationService struct { mock.Mock } -// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, formation -func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) { - ret := _m.Called(ctx, tnt, objectID, objectType, formation) +// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, formation, initialConfigurations +func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, formation model.Formation, initialConfigurations model.InitialConfigurations) (*model.Formation, error) { + ret := _m.Called(ctx, tnt, objectID, objectType, formation, initialConfigurations) if len(ret) == 0 { panic("no return value specified for AssignFormation") @@ -26,19 +26,19 @@ func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, obj var r0 *model.Formation var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) (*model.Formation, error)); ok { - return rf(ctx, tnt, objectID, objectType, formation) + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) (*model.Formation, error)); ok { + return rf(ctx, tnt, objectID, objectType, formation, initialConfigurations) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) *model.Formation); ok { - r0 = rf(ctx, tnt, objectID, objectType, formation) + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) *model.Formation); ok { + r0 = rf(ctx, tnt, objectID, objectType, formation, initialConfigurations) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.Formation) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) error); ok { - r1 = rf(ctx, tnt, objectID, objectType, formation) + if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) error); ok { + r1 = rf(ctx, tnt, objectID, objectType, formation, initialConfigurations) } else { r1 = ret.Error(1) } diff --git a/components/director/internal/domain/runtime/resolver.go b/components/director/internal/domain/runtime/resolver.go index d6b3a50205..01253dbdce 100644 --- a/components/director/internal/domain/runtime/resolver.go +++ b/components/director/internal/domain/runtime/resolver.go @@ -70,7 +70,7 @@ type ScenarioAssignmentService interface { //go:generate mockery --exported --name=formationService --output=automock --outpkg=automock --case=underscore --disable-version-string type formationService interface { GetScenariosFromMatchingASAs(ctx context.Context, objectID string, objType graphql.FormationObjectType) ([]string, error) - AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) + AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, initialConfigurations model.InitialConfigurations) (f *model.Formation, err error) ListObjectIDsOfTypeForFormations(ctx context.Context, tenantID string, formationNames []string, objectType model.FormationAssignmentType) ([]string, error) UnassignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, ignoreASA bool) (*model.Formation, error) UnassignFormationsComingFromASA(ctx context.Context, in []*model.AutomaticScenarioAssignment) error diff --git a/components/director/internal/domain/runtime/service.go b/components/director/internal/domain/runtime/service.go index 308af23848..4860c5b1bb 100644 --- a/components/director/internal/domain/runtime/service.go +++ b/components/director/internal/domain/runtime/service.go @@ -595,7 +595,7 @@ func (s *service) ensureRuntimeExists(ctx context.Context, tnt string, runtimeID func (s *service) assignRuntimeScenarios(ctx context.Context, rtmTenant, id string, scenarios []string) error { for _, scenario := range scenarios { - if _, err := s.formationService.AssignFormation(ctx, rtmTenant, id, graphql.FormationObjectTypeRuntime, model.Formation{Name: scenario}); err != nil { + if _, err := s.formationService.AssignFormation(ctx, rtmTenant, id, graphql.FormationObjectTypeRuntime, model.Formation{Name: scenario}, nil); err != nil { return errors.Wrapf(err, "while assigning formation %q from runtime with ID %q", scenario, id) } } diff --git a/components/director/internal/domain/runtime/service_test.go b/components/director/internal/domain/runtime/service_test.go index 70dfe2c06d..539f581d53 100644 --- a/components/director/internal/domain/runtime/service_test.go +++ b/components/director/internal/domain/runtime/service_test.go @@ -227,6 +227,8 @@ func TestService_CreateWithMandatoryLabels(t *testing.T) { } } + var nilInitialConfiguration model.InitialConfigurations + testCases := []struct { Name string RuntimeRepositoryFn func() *automock.RuntimeRepository @@ -333,7 +335,7 @@ func TestService_CreateWithMandatoryLabels(t *testing.T) { }, FormationServiceFn: func() *automock.FormationService { svc := &automock.FormationService{} - svc.On("AssignFormation", mock.Anything, tnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: "test"}).Return(&model.Formation{Name: "test"}, nil).Once() + svc.On("AssignFormation", mock.Anything, tnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: "test"}, nilInitialConfiguration).Return(&model.Formation{Name: "test"}, nil).Once() svc.On("GetScenariosFromMatchingASAs", ctxWithGlobalaccountMatcher, runtimeID, graphql.FormationObjectTypeRuntime).Return([]string{"test"}, nil).Once() return svc }, @@ -373,7 +375,7 @@ func TestService_CreateWithMandatoryLabels(t *testing.T) { }, FormationServiceFn: func() *automock.FormationService { svc := &automock.FormationService{} - svc.On("AssignFormation", mock.Anything, tnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: "test"}).Return(&model.Formation{Name: "test"}, nil).Once() + svc.On("AssignFormation", mock.Anything, tnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: "test"}, nilInitialConfiguration).Return(&model.Formation{Name: "test"}, nil).Once() svc.On("GetScenariosFromMatchingASAs", ctxWithGlobalaccountMatcher, runtimeID, graphql.FormationObjectTypeRuntime).Return([]string{"test"}, nil).Once() return svc }, @@ -677,7 +679,7 @@ func TestService_CreateWithMandatoryLabels(t *testing.T) { }, FormationServiceFn: func() *automock.FormationService { svc := &automock.FormationService{} - svc.On("AssignFormation", mock.Anything, tnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: "test"}).Return(nil, testErr).Once() + svc.On("AssignFormation", mock.Anything, tnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: "test"}, nilInitialConfiguration).Return(nil, testErr).Once() svc.On("GetScenariosFromMatchingASAs", ctxWithGlobalaccountMatcher, runtimeID, graphql.FormationObjectTypeRuntime).Return([]string{"test"}, nil).Once() return svc }, diff --git a/components/director/internal/domain/runtime_context/automock/formation_service.go b/components/director/internal/domain/runtime_context/automock/formation_service.go index 5c05223db3..00e5ec2b95 100644 --- a/components/director/internal/domain/runtime_context/automock/formation_service.go +++ b/components/director/internal/domain/runtime_context/automock/formation_service.go @@ -16,22 +16,29 @@ type FormationService struct { mock.Mock } -// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, formation -func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) { - ret := _m.Called(ctx, tnt, objectID, objectType, formation) +// AssignFormation provides a mock function with given fields: ctx, tnt, objectID, objectType, formation, initialConfigurations +func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, formation model.Formation, initialConfigurations model.InitialConfigurations) (*model.Formation, error) { + ret := _m.Called(ctx, tnt, objectID, objectType, formation, initialConfigurations) + + if len(ret) == 0 { + panic("no return value specified for AssignFormation") + } var r0 *model.Formation - if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) *model.Formation); ok { - r0 = rf(ctx, tnt, objectID, objectType, formation) + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) (*model.Formation, error)); ok { + return rf(ctx, tnt, objectID, objectType, formation, initialConfigurations) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) *model.Formation); ok { + r0 = rf(ctx, tnt, objectID, objectType, formation, initialConfigurations) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.Formation) } } - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation) error); ok { - r1 = rf(ctx, tnt, objectID, objectType, formation) + if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, model.InitialConfigurations) error); ok { + r1 = rf(ctx, tnt, objectID, objectType, formation, initialConfigurations) } else { r1 = ret.Error(1) } @@ -43,7 +50,15 @@ func (_m *FormationService) AssignFormation(ctx context.Context, tnt string, obj func (_m *FormationService) GetScenariosFromMatchingASAs(ctx context.Context, objectID string, objType graphql.FormationObjectType) ([]string, error) { ret := _m.Called(ctx, objectID, objType) + if len(ret) == 0 { + panic("no return value specified for GetScenariosFromMatchingASAs") + } + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, graphql.FormationObjectType) ([]string, error)); ok { + return rf(ctx, objectID, objType) + } if rf, ok := ret.Get(0).(func(context.Context, string, graphql.FormationObjectType) []string); ok { r0 = rf(ctx, objectID, objType) } else { @@ -52,7 +67,6 @@ func (_m *FormationService) GetScenariosFromMatchingASAs(ctx context.Context, ob } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, graphql.FormationObjectType) error); ok { r1 = rf(ctx, objectID, objType) } else { @@ -66,7 +80,15 @@ func (_m *FormationService) GetScenariosFromMatchingASAs(ctx context.Context, ob func (_m *FormationService) ListFormationsForObject(ctx context.Context, objectID string) ([]*model.Formation, error) { ret := _m.Called(ctx, objectID) + if len(ret) == 0 { + panic("no return value specified for ListFormationsForObject") + } + var r0 []*model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]*model.Formation, error)); ok { + return rf(ctx, objectID) + } if rf, ok := ret.Get(0).(func(context.Context, string) []*model.Formation); ok { r0 = rf(ctx, objectID) } else { @@ -75,7 +97,6 @@ func (_m *FormationService) ListFormationsForObject(ctx context.Context, objectI } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, objectID) } else { @@ -89,7 +110,15 @@ func (_m *FormationService) ListFormationsForObject(ctx context.Context, objectI func (_m *FormationService) UnassignFormation(ctx context.Context, tnt string, objectID string, objectType graphql.FormationObjectType, formation model.Formation, ignoreASA bool) (*model.Formation, error) { ret := _m.Called(ctx, tnt, objectID, objectType, formation, ignoreASA) + if len(ret) == 0 { + panic("no return value specified for UnassignFormation") + } + var r0 *model.Formation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, bool) (*model.Formation, error)); ok { + return rf(ctx, tnt, objectID, objectType, formation, ignoreASA) + } if rf, ok := ret.Get(0).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, bool) *model.Formation); ok { r0 = rf(ctx, tnt, objectID, objectType, formation, ignoreASA) } else { @@ -98,7 +127,6 @@ func (_m *FormationService) UnassignFormation(ctx context.Context, tnt string, o } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, string, graphql.FormationObjectType, model.Formation, bool) error); ok { r1 = rf(ctx, tnt, objectID, objectType, formation, ignoreASA) } else { @@ -108,13 +136,12 @@ func (_m *FormationService) UnassignFormation(ctx context.Context, tnt string, o return r0, r1 } -type mockConstructorTestingTNewFormationService interface { +// NewFormationService creates a new instance of FormationService. 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 NewFormationService(t interface { mock.TestingT Cleanup(func()) -} - -// NewFormationService creates a new instance of FormationService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewFormationService(t mockConstructorTestingTNewFormationService) *FormationService { +}) *FormationService { mock := &FormationService{} mock.Mock.Test(t) diff --git a/components/director/internal/domain/runtime_context/automock/label_repository.go b/components/director/internal/domain/runtime_context/automock/label_repository.go index de32a1e44d..9566cdd649 100644 --- a/components/director/internal/domain/runtime_context/automock/label_repository.go +++ b/components/director/internal/domain/runtime_context/automock/label_repository.go @@ -18,6 +18,10 @@ type LabelRepository struct { func (_m *LabelRepository) ListForObject(ctx context.Context, tenant string, objectType model.LabelableObject, objectID string) (map[string]*model.Label, error) { ret := _m.Called(ctx, tenant, objectType, objectID) + if len(ret) == 0 { + panic("no return value specified for ListForObject") + } + var r0 map[string]*model.Label var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, model.LabelableObject, string) (map[string]*model.Label, error)); ok { diff --git a/components/director/internal/domain/runtime_context/automock/label_upsert_service.go b/components/director/internal/domain/runtime_context/automock/label_upsert_service.go index eb8e6903b4..42c626770a 100644 --- a/components/director/internal/domain/runtime_context/automock/label_upsert_service.go +++ b/components/director/internal/domain/runtime_context/automock/label_upsert_service.go @@ -18,6 +18,10 @@ type LabelUpsertService struct { func (_m *LabelUpsertService) UpsertLabel(ctx context.Context, tenant string, labelInput *model.LabelInput) error { ret := _m.Called(ctx, tenant, labelInput) + if len(ret) == 0 { + panic("no return value specified for UpsertLabel") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *model.LabelInput) error); ok { r0 = rf(ctx, tenant, labelInput) @@ -32,6 +36,10 @@ func (_m *LabelUpsertService) UpsertLabel(ctx context.Context, tenant string, la func (_m *LabelUpsertService) UpsertMultipleLabels(ctx context.Context, tenant string, objectType model.LabelableObject, objectID string, labels map[string]interface{}) error { ret := _m.Called(ctx, tenant, objectType, objectID, labels) + if len(ret) == 0 { + panic("no return value specified for UpsertMultipleLabels") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, model.LabelableObject, string, map[string]interface{}) error); ok { r0 = rf(ctx, tenant, objectType, objectID, labels) diff --git a/components/director/internal/domain/runtime_context/automock/runtime_context_repository.go b/components/director/internal/domain/runtime_context/automock/runtime_context_repository.go index c3c8a92f34..58dc8b43f7 100644 --- a/components/director/internal/domain/runtime_context/automock/runtime_context_repository.go +++ b/components/director/internal/domain/runtime_context/automock/runtime_context_repository.go @@ -20,6 +20,10 @@ type RuntimeContextRepository struct { func (_m *RuntimeContextRepository) Create(ctx context.Context, tenant string, item *model.RuntimeContext) error { ret := _m.Called(ctx, tenant, item) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *model.RuntimeContext) error); ok { r0 = rf(ctx, tenant, item) @@ -34,6 +38,10 @@ func (_m *RuntimeContextRepository) Create(ctx context.Context, tenant string, i func (_m *RuntimeContextRepository) Delete(ctx context.Context, tenant string, id string) error { ret := _m.Called(ctx, tenant, id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { r0 = rf(ctx, tenant, id) @@ -48,6 +56,10 @@ func (_m *RuntimeContextRepository) Delete(ctx context.Context, tenant string, i func (_m *RuntimeContextRepository) Exists(ctx context.Context, tenant string, id string) (bool, error) { ret := _m.Called(ctx, tenant, id) + if len(ret) == 0 { + panic("no return value specified for Exists") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string) (bool, error)); ok { @@ -72,6 +84,10 @@ func (_m *RuntimeContextRepository) Exists(ctx context.Context, tenant string, i func (_m *RuntimeContextRepository) GetByID(ctx context.Context, tenant string, id string) (*model.RuntimeContext, error) { ret := _m.Called(ctx, tenant, id) + if len(ret) == 0 { + panic("no return value specified for GetByID") + } + var r0 *model.RuntimeContext var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string) (*model.RuntimeContext, error)); ok { @@ -98,6 +114,10 @@ func (_m *RuntimeContextRepository) GetByID(ctx context.Context, tenant string, func (_m *RuntimeContextRepository) GetForRuntime(ctx context.Context, tenant string, id string, runtimeID string) (*model.RuntimeContext, error) { ret := _m.Called(ctx, tenant, id, runtimeID) + if len(ret) == 0 { + panic("no return value specified for GetForRuntime") + } + var r0 *model.RuntimeContext var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*model.RuntimeContext, error)); ok { @@ -124,6 +144,10 @@ func (_m *RuntimeContextRepository) GetForRuntime(ctx context.Context, tenant st func (_m *RuntimeContextRepository) List(ctx context.Context, runtimeID string, tenant string, filter []*labelfilter.LabelFilter, pageSize int, cursor string) (*model.RuntimeContextPage, error) { ret := _m.Called(ctx, runtimeID, tenant, filter, pageSize, cursor) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 *model.RuntimeContextPage var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, []*labelfilter.LabelFilter, int, string) (*model.RuntimeContextPage, error)); ok { @@ -150,6 +174,10 @@ func (_m *RuntimeContextRepository) List(ctx context.Context, runtimeID string, func (_m *RuntimeContextRepository) ListAllForRuntime(ctx context.Context, tenant string, runtimeID string) ([]*model.RuntimeContext, error) { ret := _m.Called(ctx, tenant, runtimeID) + if len(ret) == 0 { + panic("no return value specified for ListAllForRuntime") + } + var r0 []*model.RuntimeContext var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]*model.RuntimeContext, error)); ok { @@ -176,6 +204,10 @@ func (_m *RuntimeContextRepository) ListAllForRuntime(ctx context.Context, tenan func (_m *RuntimeContextRepository) ListByRuntimeIDs(ctx context.Context, tenantID string, runtimeIDs []string, pageSize int, cursor string) ([]*model.RuntimeContextPage, error) { ret := _m.Called(ctx, tenantID, runtimeIDs, pageSize, cursor) + if len(ret) == 0 { + panic("no return value specified for ListByRuntimeIDs") + } + var r0 []*model.RuntimeContextPage var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []string, int, string) ([]*model.RuntimeContextPage, error)); ok { @@ -202,6 +234,10 @@ func (_m *RuntimeContextRepository) ListByRuntimeIDs(ctx context.Context, tenant func (_m *RuntimeContextRepository) Update(ctx context.Context, tenant string, item *model.RuntimeContext) error { ret := _m.Called(ctx, tenant, item) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *model.RuntimeContext) error); ok { r0 = rf(ctx, tenant, item) diff --git a/components/director/internal/domain/runtime_context/automock/runtime_repository.go b/components/director/internal/domain/runtime_context/automock/runtime_repository.go index 68502dd6ab..ef470fbac9 100644 --- a/components/director/internal/domain/runtime_context/automock/runtime_repository.go +++ b/components/director/internal/domain/runtime_context/automock/runtime_repository.go @@ -17,6 +17,10 @@ type RuntimeRepository struct { func (_m *RuntimeRepository) OwnerExists(ctx context.Context, tenant string, id string) (bool, error) { ret := _m.Called(ctx, tenant, id) + if len(ret) == 0 { + panic("no return value specified for OwnerExists") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string) (bool, error)); ok { diff --git a/components/director/internal/domain/runtime_context/automock/tenant_service.go b/components/director/internal/domain/runtime_context/automock/tenant_service.go index 447b15b7c0..0fc2a66a8f 100644 --- a/components/director/internal/domain/runtime_context/automock/tenant_service.go +++ b/components/director/internal/domain/runtime_context/automock/tenant_service.go @@ -18,6 +18,10 @@ type TenantService struct { func (_m *TenantService) GetTenantByID(ctx context.Context, id string) (*model.BusinessTenantMapping, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for GetTenantByID") + } + var r0 *model.BusinessTenantMapping var r1 error if rf, ok := ret.Get(0).(func(context.Context, string) (*model.BusinessTenantMapping, error)); ok { diff --git a/components/director/internal/domain/runtime_context/automock/uid_service.go b/components/director/internal/domain/runtime_context/automock/uid_service.go index d7a6dd6d9c..1d27cd85cb 100644 --- a/components/director/internal/domain/runtime_context/automock/uid_service.go +++ b/components/director/internal/domain/runtime_context/automock/uid_service.go @@ -13,6 +13,10 @@ type UIDService struct { func (_m *UIDService) Generate() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Generate") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() diff --git a/components/director/internal/domain/runtime_context/service.go b/components/director/internal/domain/runtime_context/service.go index 5994cea6e0..2b617a6671 100644 --- a/components/director/internal/domain/runtime_context/service.go +++ b/components/director/internal/domain/runtime_context/service.go @@ -57,7 +57,7 @@ type LabelUpsertService interface { type formationService interface { GetScenariosFromMatchingASAs(ctx context.Context, objectID string, objType graphql.FormationObjectType) ([]string, error) ListFormationsForObject(ctx context.Context, objectID string) ([]*model.Formation, error) - AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation) (*model.Formation, error) + AssignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, initialConfigurations model.InitialConfigurations) (f *model.Formation, err error) UnassignFormation(ctx context.Context, tnt, objectID string, objectType graphql.FormationObjectType, formation model.Formation, ignoreASA bool) (*model.Formation, error) } @@ -158,7 +158,7 @@ func (s *service) Create(ctx context.Context, in model.RuntimeContextInput) (str } for _, scenario := range scenariosFromAssignments { - if _, err := s.formationService.AssignFormation(ctxWithParentTenant, parentTenantID, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}); err != nil { + if _, err := s.formationService.AssignFormation(ctxWithParentTenant, parentTenantID, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}, nil); err != nil { return "", errors.Wrapf(err, "while assigning formation with name %q for runtime context", scenario) } diff --git a/components/director/internal/domain/runtime_context/service_test.go b/components/director/internal/domain/runtime_context/service_test.go index 4540a6943c..607485c097 100644 --- a/components/director/internal/domain/runtime_context/service_test.go +++ b/components/director/internal/domain/runtime_context/service_test.go @@ -129,6 +129,7 @@ func TestService_Create(t *testing.T) { ctxWithTenant := tenant.SaveToContext(ctxWithoutTenant, tnt, externalTnt) ctxWithParentTenant := tenant.SaveToContext(ctxWithTenant, parentTnt, "") formations := []string{"scenario"} + var nilConfiguration model.InitialConfigurations testCases := []struct { Name string @@ -156,7 +157,7 @@ func TestService_Create(t *testing.T) { FormationServiceFn: func() *automock.FormationService { formationSvc := &automock.FormationService{} formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once() - formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once() + formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}, nilConfiguration).Return(nil, nil).Once() return formationSvc }, RuntimeRepositoryFn: func() *automock.RuntimeRepository { @@ -188,7 +189,7 @@ func TestService_Create(t *testing.T) { FormationServiceFn: func() *automock.FormationService { formationSvc := &automock.FormationService{} formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once() - formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once() + formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}, nilConfiguration).Return(nil, nil).Once() formationSvc.On("UnassignFormation", ctxWithParentTenant, parentTnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: scenario}, true).Return(nil, nil).Once() return formationSvc }, @@ -279,7 +280,7 @@ func TestService_Create(t *testing.T) { FormationServiceFn: func() *automock.FormationService { formationSvc := &automock.FormationService{} formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once() - formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once() + formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}, nilConfiguration).Return(nil, nil).Once() formationSvc.On("UnassignFormation", ctxWithParentTenant, parentTnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: scenario}, true).Return(nil, testErr).Once() return formationSvc }, @@ -392,7 +393,7 @@ func TestService_Create(t *testing.T) { FormationServiceFn: func() *automock.FormationService { formationSvc := &automock.FormationService{} formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once() - formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, testErr).Once() + formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}, nilConfiguration).Return(nil, testErr).Once() return formationSvc }, RuntimeRepositoryFn: func() *automock.RuntimeRepository { diff --git a/components/director/internal/model/formation_assignment.go b/components/director/internal/model/formation_assignment.go index 767b732b1a..a3eaeb755b 100644 --- a/components/director/internal/model/formation_assignment.go +++ b/components/director/internal/model/formation_assignment.go @@ -21,6 +21,11 @@ const ( FormationAssignmentTypeRuntimeContext FormationAssignmentType = "RUNTIME_CONTEXT" ) +// InitialConfigurations holds the Initial configuration provided for the AssignFormation mutation. +// It is a map with key SourceID from the InitialConfiguration object and values - map with key TargetID +// from the InitialConfiguration Object and value - the configuration +type InitialConfigurations map[string]map[string]json.RawMessage + // FormationAssignment represent structure for FormationAssignment type FormationAssignment struct { ID string `json:"id"` diff --git a/components/director/pkg/graphql/graphqlizer/graphqlizer.go b/components/director/pkg/graphql/graphqlizer/graphqlizer.go index 43558cbc03..2d090a9398 100644 --- a/components/director/pkg/graphql/graphqlizer/graphqlizer.go +++ b/components/director/pkg/graphql/graphqlizer/graphqlizer.go @@ -774,6 +774,26 @@ func (g *Graphqlizer) FormationTemplateRegisterInputToGQL(in graphql.FormationTe }`) } +// InitialConfigurationToGQL missing godoc +func (g *Graphqlizer) InitialConfigurationToGQL(in graphql.InitialConfiguration) (string, error) { + return g.genericToGQL(in, `{ + sourceID: "{{ .SourceID}}" + targetID: "{{ .TargetID}}" + configuration: {{ marshal .Configuration }} + }`) +} + +// InitialConfigurationsToGQL missing godoc +func (g *Graphqlizer) InitialConfigurationsToGQL(in []*graphql.InitialConfiguration) (string, error) { + return g.genericToGQL(in, ` + [ + {{- range $i, $e := .}} + {{- if $i}}, {{- end}} {{ InitialConfigurationToGQL $e }} + {{- end }} + ], + `) +} + // FormationTemplateUpdateInputToGQL missing godoc func (g *Graphqlizer) FormationTemplateUpdateInputToGQL(in graphql.FormationTemplateUpdateInput) (string, error) { return g.genericToGQL(in, `{ @@ -1223,6 +1243,7 @@ func (g *Graphqlizer) genericToGQL(obj interface{}, tmpl string) (string, error) fm["BundleCreateInputToGQL"] = g.BundleCreateInputToGQL fm["LabelSelectorInputToGQL"] = g.LabelSelectorInputToGQL fm["OneTimeTokenInputToGQL"] = g.OneTimeTokenInputToGQL + fm["InitialConfigurationToGQL"] = g.InitialConfigurationToGQL fm["quote"] = strconv.Quote t, err := template.New("tmpl").Funcs(fm).Parse(tmpl) diff --git a/components/director/pkg/graphql/graphqlizer/graphqlizer_test.go b/components/director/pkg/graphql/graphqlizer/graphqlizer_test.go index 9444268fe0..79d18019dd 100644 --- a/components/director/pkg/graphql/graphqlizer/graphqlizer_test.go +++ b/components/director/pkg/graphql/graphqlizer/graphqlizer_test.go @@ -13,7 +13,6 @@ import ( func TestGraphqlizer_LabelsToGQL(t *testing.T) { // GIVEN g := graphqlizer.Graphqlizer{} - testCases := []struct { Name string Input graphql.Labels diff --git a/components/director/pkg/graphql/models_gen.go b/components/director/pkg/graphql/models_gen.go index 8788c49c5b..8861dc77fe 100644 --- a/components/director/pkg/graphql/models_gen.go +++ b/components/director/pkg/graphql/models_gen.go @@ -696,6 +696,12 @@ type HealthCheckPage struct { func (HealthCheckPage) IsPageable() {} +type InitialConfiguration struct { + SourceID string `json:"sourceID"` + TargetID string `json:"targetID"` + Configuration JSON `json:"configuration"` +} + type IntSysSystemAuth struct { ID string `json:"id"` Auth *Auth `json:"auth,omitempty"` diff --git a/components/director/pkg/graphql/schema.graphql b/components/director/pkg/graphql/schema.graphql index ee1ec5ac17..5894fc4fa2 100644 --- a/components/director/pkg/graphql/schema.graphql +++ b/components/director/pkg/graphql/schema.graphql @@ -819,6 +819,12 @@ input FormationTemplateUpdateInput { discoveryConsumers: [String!] } +input InitialConfiguration { + sourceID: ID! + targetID: ID! + configuration: JSON! +} + input IntegrationDependencyInput { name: String! description: String @@ -2098,7 +2104,7 @@ type Mutation { - [assign runtime to formation](examples/assign-formation/assign-runtime-to-formation.graphql) - [assign tenant to formation](examples/assign-formation/assign-tenant-to-formation.graphql) """ - assignFormation(objectID: ID!, objectType: FormationObjectType!, formation: FormationInput!): Formation! @hasScopes(path: "graphql.mutation.assignFormation") + assignFormation(objectID: ID!, objectType: FormationObjectType!, formation: FormationInput!, initialConfigurations: [InitialConfiguration!]): Formation! @hasScopes(path: "graphql.mutation.assignFormation") """ **Examples** - [unassign application from formation](examples/unassign-formation/unassign-application-from-formation.graphql) diff --git a/components/director/pkg/graphql/schema_gen.go b/components/director/pkg/graphql/schema_gen.go index 5dbc92e190..cfbbc319ba 100644 --- a/components/director/pkg/graphql/schema_gen.go +++ b/components/director/pkg/graphql/schema_gen.go @@ -578,7 +578,7 @@ type ComplexityRoot struct { AddIntegrationDependencyToApplication func(childComplexity int, appID string, in IntegrationDependencyInput) int AddTenantAccess func(childComplexity int, in TenantAccessInput) int AddWebhook func(childComplexity int, applicationID *string, applicationTemplateID *string, runtimeID *string, formationTemplateID *string, in WebhookInput) int - AssignFormation func(childComplexity int, objectID string, objectType FormationObjectType, formation FormationInput) int + AssignFormation func(childComplexity int, objectID string, objectType FormationObjectType, formation FormationInput, initialConfigurations []*InitialConfiguration) int AttachConstraintToFormationTemplate func(childComplexity int, constraintID string, formationTemplateID string) int CreateApplicationTemplate func(childComplexity int, in ApplicationTemplateInput) int CreateBundleInstanceAuth func(childComplexity int, bundleID string, in BundleInstanceAuthCreateInput) int @@ -1002,7 +1002,7 @@ type MutationResolver interface { ResynchronizeFormationNotifications(ctx context.Context, formationID string, reset *bool) (*Formation, error) FinalizeDraftFormation(ctx context.Context, formationID string) (*Formation, error) DeleteFormation(ctx context.Context, formation FormationInput) (*Formation, error) - AssignFormation(ctx context.Context, objectID string, objectType FormationObjectType, formation FormationInput) (*Formation, error) + AssignFormation(ctx context.Context, objectID string, objectType FormationObjectType, formation FormationInput, initialConfigurations []*InitialConfiguration) (*Formation, error) UnassignFormation(ctx context.Context, objectID string, objectType FormationObjectType, formation FormationInput) (*Formation, error) UnassignFormationGlobal(ctx context.Context, objectID string, objectType FormationObjectType, formation string) (*Formation, error) CreateFormationConstraint(ctx context.Context, formationConstraint FormationConstraintInput) (*FormationConstraint, error) @@ -3618,7 +3618,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.AssignFormation(childComplexity, args["objectID"].(string), args["objectType"].(FormationObjectType), args["formation"].(FormationInput)), true + return e.complexity.Mutation.AssignFormation(childComplexity, args["objectID"].(string), args["objectType"].(FormationObjectType), args["formation"].(FormationInput), args["initialConfigurations"].([]*InitialConfiguration)), true case "Mutation.attachConstraintToFormationTemplate": if e.complexity.Mutation.AttachConstraintToFormationTemplate == nil { @@ -5966,6 +5966,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputFormationInput, ec.unmarshalInputFormationTemplateRegisterInput, ec.unmarshalInputFormationTemplateUpdateInput, + ec.unmarshalInputInitialConfiguration, ec.unmarshalInputIntegrationDependencyInput, ec.unmarshalInputIntegrationSystemInput, ec.unmarshalInputLabelDefinitionInput, @@ -6936,6 +6937,15 @@ func (ec *executionContext) field_Mutation_assignFormation_args(ctx context.Cont } } args["formation"] = arg2 + var arg3 []*InitialConfiguration + if tmp, ok := rawArgs["initialConfigurations"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("initialConfigurations")) + arg3, err = ec.unmarshalOInitialConfiguration2ᚕᚖgithubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐInitialConfigurationᚄ(ctx, tmp) + if err != nil { + return nil, err + } + } + args["initialConfigurations"] = arg3 return args, nil } @@ -31256,7 +31266,7 @@ func (ec *executionContext) _Mutation_assignFormation(ctx context.Context, field resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { directive0 := func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AssignFormation(rctx, fc.Args["objectID"].(string), fc.Args["objectType"].(FormationObjectType), fc.Args["formation"].(FormationInput)) + return ec.resolvers.Mutation().AssignFormation(rctx, fc.Args["objectID"].(string), fc.Args["objectType"].(FormationObjectType), fc.Args["formation"].(FormationInput), fc.Args["initialConfigurations"].([]*InitialConfiguration)) } directive1 := func(ctx context.Context) (interface{}, error) { path, err := ec.unmarshalNString2string(ctx, "graphql.mutation.assignFormation") @@ -48378,6 +48388,47 @@ func (ec *executionContext) unmarshalInputFormationTemplateUpdateInput(ctx conte return it, nil } +func (ec *executionContext) unmarshalInputInitialConfiguration(ctx context.Context, obj interface{}) (InitialConfiguration, error) { + var it InitialConfiguration + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"sourceID", "targetID", "configuration"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "sourceID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sourceID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.SourceID = data + case "targetID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("targetID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.TargetID = data + case "configuration": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("configuration")) + data, err := ec.unmarshalNJSON2githubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐJSON(ctx, v) + if err != nil { + return it, err + } + it.Configuration = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputIntegrationDependencyInput(ctx context.Context, obj interface{}) (IntegrationDependencyInput, error) { var it IntegrationDependencyInput asMap := map[string]interface{}{} @@ -58579,6 +58630,11 @@ func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.Selec return res } +func (ec *executionContext) unmarshalNInitialConfiguration2ᚖgithubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐInitialConfiguration(ctx context.Context, v interface{}) (*InitialConfiguration, error) { + res, err := ec.unmarshalInputInitialConfiguration(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { res, err := graphql.UnmarshalInt(v) return res, graphql.ErrorOnPath(ctx, err) @@ -58744,6 +58800,16 @@ func (ec *executionContext) marshalNIntegrationSystemPage2ᚖgithubᚗcomᚋkyma return ec._IntegrationSystemPage(ctx, sel, v) } +func (ec *executionContext) unmarshalNJSON2githubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐJSON(ctx context.Context, v interface{}) (JSON, error) { + var res JSON + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNJSON2githubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐJSON(ctx context.Context, sel ast.SelectionSet, v JSON) graphql.Marshaler { + return v +} + func (ec *executionContext) marshalNLabel2githubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐLabel(ctx context.Context, sel ast.SelectionSet, v Label) graphql.Marshaler { return ec._Label(ctx, sel, &v) } @@ -60788,6 +60854,26 @@ func (ec *executionContext) marshalOID2ᚖstring(ctx context.Context, sel ast.Se return res } +func (ec *executionContext) unmarshalOInitialConfiguration2ᚕᚖgithubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐInitialConfigurationᚄ(ctx context.Context, v interface{}) ([]*InitialConfiguration, error) { + if v == nil { + return nil, nil + } + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]*InitialConfiguration, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalNInitialConfiguration2ᚖgithubᚗcomᚋkymaᚑincubatorᚋcompassᚋcomponentsᚋdirectorᚋpkgᚋgraphqlᚐInitialConfiguration(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { if v == nil { return nil, nil diff --git a/tests/director/tests/notifications/application_only_notifications_new_format_test.go b/tests/director/tests/notifications/application_only_notifications_new_format_test.go index 275778fcf8..a84f1f24d9 100644 --- a/tests/director/tests/notifications/application_only_notifications_new_format_test.go +++ b/tests/director/tests/notifications/application_only_notifications_new_format_test.go @@ -234,6 +234,89 @@ func TestFormationNotificationsWithApplicationOnlyParticipantsNewFormat(t *testi op.Execute(t, ctx, certSecuredGraphQLClient) }) + t.Run("Initial Configuration", func(t *testing.T) { + cleanupNotificationsFromExternalSvcMock(t, certSecuredHTTPClient) + defer cleanupNotificationsFromExternalSvcMock(t, certSecuredHTTPClient) + + t.Logf("Add webhook with type: %q and mode: %q to application with ID: %q", graphql.WebhookTypeApplicationTenantMapping, graphql.WebhookModeSync, app1ID) + op := operations.NewAddWebhookToObjectOperation(graphql.WebhookTypeApplicationTenantMapping, operations.WebhookReferenceObjectTypeApplication, app1ID, tnt). + WithWebhookMode(graphql.WebhookModeSync). + WithURLTemplate("{\\\"path\\\":\\\"" + conf.ExternalServicesMockMtlsSecuredURL + "/formation-callback/{{.TargetApplication.ID}}{{if eq .Operation \\\"unassign\\\"}}/{{.SourceApplication.ID}}{{end}}\\\",\\\"method\\\":\\\"{{if eq .Operation \\\"assign\\\"}}PATCH{{else}}DELETE{{end}}\\\"}"). + WithInputTemplate("{\\\"context\\\":{\\\"crmId\\\":\\\"{{.CustomerTenantContext.CustomerID}}\\\",\\\"globalAccountId\\\":\\\"{{.CustomerTenantContext.AccountID}}\\\",\\\"uclFormationId\\\":\\\"{{.FormationID}}\\\",\\\"uclFormationName\\\":\\\"{{.Formation.Name}}\\\",\\\"operation\\\":\\\"{{.Operation}}\\\"},\\\"receiverTenant\\\":{\\\"state\\\":\\\"{{.Assignment.State}}\\\",\\\"uclAssignmentId\\\":\\\"{{.Assignment.ID}}\\\",\\\"deploymentRegion\\\":\\\"{{if .TargetApplication.Labels.region}}{{.TargetApplication.Labels.region}}{{else}}{{.TargetApplicationTemplate.Labels.region}}{{end}}\\\",\\\"applicationNamespace\\\":\\\"{{.TargetApplicationTemplate.ApplicationNamespace}}\\\",\\\"applicationUrl\\\":\\\"{{.TargetApplication.BaseURL}}\\\",\\\"applicationTenantId\\\":\\\"{{.TargetApplication.LocalTenantID}}\\\",\\\"uclSystemName\\\":\\\"{{.TargetApplication.Name}}\\\",\\\"uclSystemTenantId\\\":\\\"{{.TargetApplication.ID}}\\\",\\\"configuration\\\":{{.Assignment.Value}}},\\\"assignedTenant\\\":{\\\"state\\\":\\\"{{.ReverseAssignment.State}}\\\",\\\"uclAssignmentId\\\":\\\"{{.ReverseAssignment.ID}}\\\",\\\"deploymentRegion\\\":\\\"{{if .SourceApplication.Labels.region}}{{.SourceApplication.Labels.region}}{{else}}{{.SourceApplicationTemplate.Labels.region}}{{end}}\\\",\\\"applicationNamespace\\\":\\\"{{.SourceApplicationTemplate.ApplicationNamespace}}\\\",\\\"applicationUrl\\\":\\\"{{.SourceApplication.BaseURL}}\\\",\\\"applicationTenantId\\\":\\\"{{.SourceApplication.LocalTenantID}}\\\",\\\"uclSystemName\\\":\\\"{{.SourceApplication.Name}}\\\",\\\"uclSystemTenantId\\\":\\\"{{.SourceApplication.ID}}\\\",\\\"configuration\\\":{{.ReverseAssignment.Value}}}}"). + WithOutputTemplate("{\\\"config\\\":\\\"{{.Body.config}}\\\", \\\"location\\\":\\\"{{.Headers.Location}}\\\",\\\"error\\\": \\\"{{.Body.error}}\\\",\\\"success_status_code\\\": 200, \\\"incomplete_status_code\\\": 204}").Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + + t.Logf("Assign application 1 to formation: %s", formationName) + expectationsBuilder = mock_data.NewFAExpectationsBuilder().WithParticipant(app1ID) + asserter := asserters.NewFormationAssignmentAsserter(expectationsBuilder.GetExpectations(), expectationsBuilder.GetExpectedAssignmentsCount(), certSecuredGraphQLClient, tnt) + statusAsserter := asserters.NewFormationStatusAsserter(tnt, certSecuredGraphQLClient) + op = operations.NewAssignAppToFormationOperation(app1ID, tnt).WithAsserters(asserter, statusAsserter).Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + + t.Logf("Assign application 2 to formation: %s", formationName) + expectationsBuilder = mock_data.NewFAExpectationsBuilder(). + WithParticipant(app1ID). + WithParticipant(app2ID). + WithNotifications([]*mock_data.NotificationData{ + mock_data.NewNotificationData(app2ID, app1ID, readyAssignmentState, fixtures.StatusAPISyncConfigJSON, nil), + mock_data.NewNotificationData(app1ID, app2ID, readyAssignmentState, &fixtures.InitialConfiguration1, nil), + }) + faAsserter := asserters.NewFormationAssignmentAsserter(expectationsBuilder.GetExpectations(), expectationsBuilder.GetExpectedAssignmentsCount(), certSecuredGraphQLClient, tnt) + statusAsserter = asserters.NewFormationStatusAsserter(tnt, certSecuredGraphQLClient) + notificationsAsserter := asserters.NewNotificationsAsserter(1, assignOperation, app1ID, app2ID, localTenantID, appNamespace, appRegion, tnt, tntParentCustomer, &fixtures.InitialConfiguration2, conf.ExternalServicesMockMtlsSecuredURL, certSecuredHTTPClient) + op = operations.NewAssignAppToFormationOperation(app2ID, tnt). + WithInitialConfiguration([]*graphql.InitialConfiguration{ + {SourceID: app1ID, TargetID: app2ID, Configuration: graphql.JSON(fixtures.InitialConfiguration1)}, + {SourceID: app2ID, TargetID: app1ID, Configuration: graphql.JSON(fixtures.InitialConfiguration2)}, + }). + WithAsserters(faAsserter, statusAsserter, notificationsAsserter).Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + + t.Logf("Unassign Application 1 from formation: %s", formationName) + expectationsBuilder = mock_data.NewFAExpectationsBuilder().WithParticipant(app2ID) + faAsserter = asserters.NewFormationAssignmentAsserter(expectationsBuilder.GetExpectations(), expectationsBuilder.GetExpectedAssignmentsCount(), certSecuredGraphQLClient, tnt) + statusAsserter = asserters.NewFormationStatusAsserter(tnt, certSecuredGraphQLClient) + unassignNotificationsAsserter := asserters.NewUnassignNotificationsAsserter(1, app1ID, app2ID, localTenantID, appNamespace, appRegion, tnt, tntParentCustomer, "", conf.ExternalServicesMockMtlsSecuredURL, certSecuredHTTPClient) + op = operations.NewUnassignAppFromFormationOperation(app1ID, tnt).WithAsserters(faAsserter, statusAsserter, unassignNotificationsAsserter).Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + + t.Logf("Assign application 1 to formation: %s again", formationName) + expectationsBuilder = mock_data.NewFAExpectationsBuilder(). + WithParticipant(app1ID). + WithParticipant(app2ID). + WithNotifications([]*mock_data.NotificationData{ + mock_data.NewNotificationData(app2ID, app1ID, readyAssignmentState, fixtures.StatusAPISyncConfigJSON, nil), + }) + asserter = asserters.NewFormationAssignmentAsserter(expectationsBuilder.GetExpectations(), expectationsBuilder.GetExpectedAssignmentsCount(), certSecuredGraphQLClient, tnt) + statusAsserter = asserters.NewFormationStatusAsserter(tnt, certSecuredGraphQLClient) + notificationsAsserter = asserters.NewNotificationsAsserter(3, assignOperation, app1ID, app2ID, localTenantID, appNamespace, appRegion, tnt, tntParentCustomer, &emptyConfig, conf.ExternalServicesMockMtlsSecuredURL, certSecuredHTTPClient) + op = operations.NewAssignAppToFormationOperation(app1ID, tnt).WithAsserters(asserter, statusAsserter, notificationsAsserter).Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + + t.Logf("Unassign Application 2 from formation: %s", formationName) + expectationsBuilder = mock_data.NewFAExpectationsBuilder(). + WithParticipant(app1ID) + faAsserter = asserters.NewFormationAssignmentAsserter(expectationsBuilder.GetExpectations(), expectationsBuilder.GetExpectedAssignmentsCount(), certSecuredGraphQLClient, tnt) + statusAsserter = asserters.NewFormationStatusAsserter(tnt, certSecuredGraphQLClient) + unassignNotificationsAsserter = asserters.NewUnassignNotificationsAsserter(2, app1ID, app2ID, localTenantID, appNamespace, appRegion, tnt, tntParentCustomer, "", conf.ExternalServicesMockMtlsSecuredURL, certSecuredHTTPClient) + op = operations.NewUnassignAppFromFormationOperation(app2ID, tnt).WithAsserters(faAsserter, statusAsserter, unassignNotificationsAsserter).Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + + t.Logf("Unassign Application 1 from formation: %s", formationName) + expectationsBuilder = mock_data.NewFAExpectationsBuilder() + faAsserter = asserters.NewFormationAssignmentAsserter(expectationsBuilder.GetExpectations(), expectationsBuilder.GetExpectedAssignmentsCount(), certSecuredGraphQLClient, tnt) + statusAsserter = asserters.NewFormationStatusAsserter(tnt, certSecuredGraphQLClient) + op = operations.NewUnassignAppFromFormationOperation(app1ID, tnt).WithAsserters(faAsserter, statusAsserter).Operation() + defer op.Cleanup(t, ctx, certSecuredGraphQLClient) + op.Execute(t, ctx, certSecuredGraphQLClient) + }) + t.Run("Synchronous App to App Formation Assignment Notifications when state is in the response body", func(t *testing.T) { cleanupNotificationsFromExternalSvcMock(t, certSecuredHTTPClient) defer cleanupNotificationsFromExternalSvcMock(t, certSecuredHTTPClient) diff --git a/tests/go.mod b/tests/go.mod index e6165db8d7..c5688461de 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -4,10 +4,11 @@ go 1.20 require ( github.com/avast/retry-go/v4 v4.5.0 + github.com/davecgh/go-spew v1.1.1 github.com/google/uuid v1.6.0 github.com/kyma-incubator/compass/components/connectivity-adapter v0.0.0-20240527112649-67c34c9b27d5 github.com/kyma-incubator/compass/components/connector v0.0.0-20240527112649-67c34c9b27d5 - github.com/kyma-incubator/compass/components/director v0.0.0-20240527112649-67c34c9b27d5 + github.com/kyma-incubator/compass/components/director v0.0.0-20240606125859-e84827ae24a2 github.com/kyma-incubator/compass/components/external-services-mock v0.0.0-20240527112649-67c34c9b27d5 github.com/kyma-incubator/compass/components/gateway v0.0.0-20240527112649-67c34c9b27d5 github.com/kyma-incubator/compass/components/operations-controller v0.0.0-20240527112649-67c34c9b27d5 @@ -33,7 +34,6 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index fa8dce4eef..8687628df4 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -124,8 +124,8 @@ github.com/kyma-incubator/compass/components/connectivity-adapter v0.0.0-2024052 github.com/kyma-incubator/compass/components/connectivity-adapter v0.0.0-20240527112649-67c34c9b27d5/go.mod h1:eiUBe1oKvgOWTISq4sHITaTe+EPHHpeEuBuc9kqUy60= github.com/kyma-incubator/compass/components/connector v0.0.0-20240527112649-67c34c9b27d5 h1:tMDm3pA8y978ztVFUzWy8EtAC3NGfxpmmA/Io7gBxao= github.com/kyma-incubator/compass/components/connector v0.0.0-20240527112649-67c34c9b27d5/go.mod h1:xABaWcMLMj/m3ETwv5Sn5oUosGP/wmByE47MJy553ws= -github.com/kyma-incubator/compass/components/director v0.0.0-20240527112649-67c34c9b27d5 h1:3G3OJX8kofXO86wYcMqTXV8rHbZC2nj4msTn7z0DQeE= -github.com/kyma-incubator/compass/components/director v0.0.0-20240527112649-67c34c9b27d5/go.mod h1:yA8bwdN91TwMGKiG69/xHGjgpmkJkZM9GTCHj+Y+9rA= +github.com/kyma-incubator/compass/components/director v0.0.0-20240606125859-e84827ae24a2 h1:NTMVce5QbyYeIO+H4/D01VCgrZqzd+DNGTnMw36F4WA= +github.com/kyma-incubator/compass/components/director v0.0.0-20240606125859-e84827ae24a2/go.mod h1:yb/eFo/dnRGGAiW5WOYUFdygDNwZLGgLpd/xtzEX1eM= github.com/kyma-incubator/compass/components/external-services-mock v0.0.0-20240527112649-67c34c9b27d5 h1:OfpceYk4y0b0c+HWVFuY3CfuoWplTUEmtRUCFQITRqU= github.com/kyma-incubator/compass/components/external-services-mock v0.0.0-20240527112649-67c34c9b27d5/go.mod h1:4jSa7fSRyBFyF9OsJu0EtkgYV5H35IzGHFJC4OBhes4= github.com/kyma-incubator/compass/components/gateway v0.0.0-20240527112649-67c34c9b27d5 h1:9Z/tl5TgernZ2HfNiLb16avTXFp59O2mYV4NywFOtqs= diff --git a/tests/pkg/fixtures/fomation_requests.go b/tests/pkg/fixtures/fomation_requests.go index 03d3758286..10d6aa26e1 100644 --- a/tests/pkg/fixtures/fomation_requests.go +++ b/tests/pkg/fixtures/fomation_requests.go @@ -93,6 +93,15 @@ func FixAssignFormationRequest(objID, objType, formationName string) *gcli.Reque }`, objID, objType, formationName, testctx.Tc.GQLFieldsProvider.ForFormationWithStatus())) } +func FixAssignFormationRequestWithInitialConfigurations(objID, objType, formationName, initialConfigurations string) *gcli.Request { + return gcli.NewRequest( + fmt.Sprintf(`mutation{ + result: assignFormation(objectID:"%s",objectType: %s ,formation: {name: "%s"}, initialConfigurations: %s){ + %s + } + }`, objID, objType, formationName, initialConfigurations, testctx.Tc.GQLFieldsProvider.ForFormationWithStatus())) +} + func FixUnassignFormationRequest(objID, objType, formationName string) *gcli.Request { return gcli.NewRequest( fmt.Sprintf(`mutation{ diff --git a/tests/pkg/fixtures/formation_assignment_notifications_constants.go b/tests/pkg/fixtures/formation_assignment_notifications_constants.go index bfb928558d..e3f7bc6ddc 100644 --- a/tests/pkg/fixtures/formation_assignment_notifications_constants.go +++ b/tests/pkg/fixtures/formation_assignment_notifications_constants.go @@ -15,7 +15,8 @@ var ( StatusAPIAsyncConfigJSON = str.Ptr("{\"asyncKey\":\"asyncValue\",\"asyncKey2\":{\"asyncNestedKey\":\"asyncNestedValue\"}}") StatusAPIResetConfigJSON = str.Ptr("{\"resetKey\":\"resetValue\",\"resetKey2\":{\"resetKey\":\"resetValue2\"}}") StatusAPISyncErrorMessageJSON = str.Ptr("{\"error\":{\"message\":\"failed to parse request\",\"errorCode\":2}}") - RedirectConfigJSON = str.Ptr("{\"redirectProperties\":[{\"redirectPropertyName\":\"redirectName\",\"redirectPropertyID\":\"redirectID\"}]}") + InitialConfiguration1 = "{\"initial\":\"configuration\"}" + InitialConfiguration2 = "{\"initial\":\"configuration2\"}" StatusAPISyncError = &graphql.FormationStatusError{ Message: StatusAPISyncErrorMessage, ErrorCode: 2, diff --git a/tests/pkg/fixtures/formation_queries.go b/tests/pkg/fixtures/formation_queries.go index c5f2ea6bf8..74ecd87648 100644 --- a/tests/pkg/fixtures/formation_queries.go +++ b/tests/pkg/fixtures/formation_queries.go @@ -131,7 +131,7 @@ func DeleteFormationWithinTenantExpectError(t *testing.T, ctx context.Context, g } func AssignFormationWithTenantObjectType(t require.TestingT, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, tenantID, parent string) *graphql.Formation { - return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, tenantID, string(graphql.FormationObjectTypeTenant), parent) + return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, tenantID, string(graphql.FormationObjectTypeTenant), parent, "") } func AssignFormationWithTenantObjectTypeExpectError(t *testing.T, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, tenantID, parent string) *graphql.Formation { @@ -171,7 +171,14 @@ func UnassignFormationApplicationGlobal(t require.TestingT, ctx context.Context, } func AssignFormationWithApplicationObjectType(t require.TestingT, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, appID, tenantID string) *graphql.Formation { - return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, appID, string(graphql.FormationObjectTypeApplication), tenantID) + return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, appID, string(graphql.FormationObjectTypeApplication), tenantID, "") +} + +func AssignFormationWithInitialConfigurations(t require.TestingT, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, objectID, objectType, tenantID string, initialConfigurations []*graphql.InitialConfiguration) *graphql.Formation { + configurationsString, err := testctx.Tc.Graphqlizer.InitialConfigurationsToGQL(initialConfigurations) + require.NoError(t, err) + + return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, objectID, objectType, tenantID, configurationsString) } func AssignFormationWithApplicationObjectTypeExpectError(t *testing.T, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, appID, tenantID string) *graphql.Formation { @@ -183,7 +190,7 @@ func UnassignFormationWithApplicationObjectType(t require.TestingT, ctx context. } func AssignFormationWithRuntimeObjectType(t require.TestingT, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, runtimeID, tenantID string) *graphql.Formation { - return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, runtimeID, string(graphql.FormationObjectTypeRuntime), tenantID) + return assignFormationWithCustomObjectType(t, ctx, gqlClient, in, runtimeID, string(graphql.FormationObjectTypeRuntime), tenantID, "") } func AssignFormationWithRuntimeObjectTypeExpectError(t *testing.T, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, runtimeID, tenantID string) *graphql.Formation { @@ -202,8 +209,15 @@ func UnassignFormationWithRuntimeContextObjectType(t require.TestingT, ctx conte return unassignFormationWithCustomObjectType(t, ctx, gqlClient, in, runtimeContextID, string(graphql.FormationObjectTypeRuntimeContext), tenantID) } -func assignFormationWithCustomObjectType(t require.TestingT, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, objectID, objectType, tenantID string) *graphql.Formation { - createRequest := FixAssignFormationRequest(objectID, objectType, in.Name) +func assignFormationWithCustomObjectType(t require.TestingT, ctx context.Context, gqlClient *gcli.Client, in graphql.FormationInput, objectID, objectType, tenantID, initialConfigurations string) *graphql.Formation { + var createRequest *gcli.Request + + if initialConfigurations != "" { + createRequest = FixAssignFormationRequestWithInitialConfigurations(objectID, objectType, in.Name, initialConfigurations) + } else { + createRequest = FixAssignFormationRequest(objectID, objectType, in.Name) + + } formation := graphql.Formation{} diff --git a/tests/pkg/fixtures/operations_requests.go b/tests/pkg/fixtures/operations_requests.go index 56993b7cba..87fe7238b0 100644 --- a/tests/pkg/fixtures/operations_requests.go +++ b/tests/pkg/fixtures/operations_requests.go @@ -2,6 +2,7 @@ package fixtures import ( "fmt" + "github.com/kyma-incubator/compass/tests/pkg/testctx" gcli "github.com/machinebox/graphql" ) diff --git a/tests/pkg/notifications/asserters/formation_assignments.go b/tests/pkg/notifications/asserters/formation_assignments.go index fa03c0365e..ed8d8eedab 100644 --- a/tests/pkg/notifications/asserters/formation_assignments.go +++ b/tests/pkg/notifications/asserters/formation_assignments.go @@ -2,13 +2,14 @@ package asserters import ( "context" + "testing" + gql "github.com/kyma-incubator/compass/components/director/pkg/graphql" "github.com/kyma-incubator/compass/components/director/pkg/str" "github.com/kyma-incubator/compass/tests/pkg/fixtures" context_keys "github.com/kyma-incubator/compass/tests/pkg/notifications/context-keys" "github.com/machinebox/graphql" "github.com/stretchr/testify/require" - "testing" ) type FormationAssignmentsAsserter struct { diff --git a/tests/pkg/notifications/operations/assign_application.go b/tests/pkg/notifications/operations/assign_application.go index 079a95fc7c..eb6178e724 100644 --- a/tests/pkg/notifications/operations/assign_application.go +++ b/tests/pkg/notifications/operations/assign_application.go @@ -15,6 +15,7 @@ type AssignAppToFormationOperation struct { applicationID string tenantID string formationName string + initialConfigurations []*graphql.InitialConfiguration formationNameContextKey string asserters []asserters.Asserter } @@ -28,6 +29,11 @@ func (o *AssignAppToFormationOperation) WithFormationNameContextKey(formationNAm return o } +func (o *AssignAppToFormationOperation) WithInitialConfiguration(initialConfigurations []*graphql.InitialConfiguration) *AssignAppToFormationOperation { + o.initialConfigurations = initialConfigurations + return o +} + func (o *AssignAppToFormationOperation) WithAsserters(asserters ...asserters.Asserter) *AssignAppToFormationOperation { for i, _ := range asserters { o.asserters = append(o.asserters, asserters[i]) @@ -48,7 +54,12 @@ func (o *AssignAppToFormationOperation) Execute(t *testing.T, ctx context.Contex formationName = ctx.Value(o.formationNameContextKey).(string) } - fixtures.AssignFormationWithApplicationObjectType(t, ctx, gqlClient, graphql.FormationInput{Name: formationName}, o.applicationID, o.tenantID) + if o.initialConfigurations != nil { + fixtures.AssignFormationWithInitialConfigurations(t, ctx, gqlClient, graphql.FormationInput{Name: formationName}, o.applicationID, string(graphql.FormationObjectTypeApplication), o.tenantID, o.initialConfigurations) + } else { + fixtures.AssignFormationWithApplicationObjectType(t, ctx, gqlClient, graphql.FormationInput{Name: formationName}, o.applicationID, o.tenantID) + } + for _, asserter := range o.asserters { asserter.AssertExpectations(t, ctx) } diff --git a/tests/pkg/notifications/operations/cleanup_notifications.go b/tests/pkg/notifications/operations/cleanup_notifications.go index 75ed247685..8d545297b0 100644 --- a/tests/pkg/notifications/operations/cleanup_notifications.go +++ b/tests/pkg/notifications/operations/cleanup_notifications.go @@ -2,11 +2,12 @@ package operations import ( "context" + "net/http" + "testing" + "github.com/kyma-incubator/compass/tests/pkg/notifications/asserters" gcli "github.com/machinebox/graphql" "github.com/stretchr/testify/require" - "net/http" - "testing" ) type CleanupNotificationsOperation struct { diff --git a/tests/pkg/notifications/operations/unassign_application.go b/tests/pkg/notifications/operations/unassign_application.go index 13eb6347f7..df8580b9bd 100644 --- a/tests/pkg/notifications/operations/unassign_application.go +++ b/tests/pkg/notifications/operations/unassign_application.go @@ -2,12 +2,13 @@ package operations import ( "context" + "testing" + "github.com/kyma-incubator/compass/components/director/pkg/graphql" "github.com/kyma-incubator/compass/tests/pkg/fixtures" "github.com/kyma-incubator/compass/tests/pkg/notifications/asserters" context_keys "github.com/kyma-incubator/compass/tests/pkg/notifications/context-keys" gcli "github.com/machinebox/graphql" - "testing" ) type UnassignAppFromFormationOperation struct {