github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/formationassignment/notifications_test.go (about)

     1  package formationassignment_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/pkg/formationconstraint"
     9  
    10  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    11  
    12  	databuilderautomock "github.com/kyma-incubator/compass/components/director/internal/domain/webhook/datainputbuilder/automock"
    13  
    14  	"github.com/kyma-incubator/compass/components/director/internal/domain/formationassignment"
    15  	"github.com/kyma-incubator/compass/components/director/internal/domain/formationassignment/automock"
    16  	"github.com/kyma-incubator/compass/components/director/internal/model"
    17  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    18  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    19  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    20  	tnt "github.com/kyma-incubator/compass/components/director/pkg/tenant"
    21  	"github.com/kyma-incubator/compass/components/director/pkg/webhook"
    22  	webhookclient "github.com/kyma-incubator/compass/components/director/pkg/webhook_client"
    23  	"github.com/stretchr/testify/mock"
    24  	"github.com/stretchr/testify/require"
    25  )
    26  
    27  var (
    28  	testRuntimeID     = "testRuntimeID"
    29  	testAppTemplateID = "testAppTemplateID"
    30  
    31  	testAppWebhook = &model.Webhook{
    32  		ID:         "TestAppWebhookID",
    33  		ObjectID:   TestSource,
    34  		ObjectType: model.ApplicationWebhookReference,
    35  	}
    36  
    37  	testRuntimeWebhook = &model.Webhook{
    38  		ID:         "TestRuntimeWebhookID",
    39  		ObjectID:   TestSource,
    40  		ObjectType: model.RuntimeWebhookReference,
    41  	}
    42  
    43  	testRuntimeWithLabels = &webhook.RuntimeWithLabels{
    44  		Runtime: &model.Runtime{
    45  			Name: "testRuntimeName",
    46  		},
    47  		Labels: testLabels,
    48  	}
    49  	testRuntimeCtxWithLabels = &webhook.RuntimeContextWithLabels{
    50  		RuntimeContext: &model.RuntimeContext{
    51  			ID:        "testRuntimeCtxID",
    52  			RuntimeID: testRuntimeID,
    53  			Key:       "testKey",
    54  			Value:     "testValue",
    55  		},
    56  		Labels: testLabels,
    57  	}
    58  
    59  	testLabels        = map[string]string{"testLabelKey": "testLabelValue"}
    60  	testAppWithLabels = &webhook.ApplicationWithLabels{
    61  		Application: &model.Application{
    62  			Name:                  "testAppName",
    63  			ApplicationTemplateID: str.Ptr(testAppTemplateID),
    64  		},
    65  		Labels: testLabels,
    66  	}
    67  	testAppTemplateWithLabels = &webhook.ApplicationTemplateWithLabels{
    68  		ApplicationTemplate: &model.ApplicationTemplate{
    69  			ID:   testAppTemplateID,
    70  			Name: "testAppTemplateName",
    71  		},
    72  		Labels: testLabels,
    73  	}
    74  
    75  	testGqlAppWebhook = &graphql.Webhook{
    76  		ID:   testAppWebhook.ID,
    77  		Type: graphql.WebhookType(testAppWebhook.Type),
    78  	}
    79  
    80  	testCustomerTenantContext = &webhook.CustomerTenantContext{
    81  		CustomerID: TntParentID,
    82  		AccountID:  str.Ptr(TestTenantID),
    83  		Path:       nil,
    84  	}
    85  
    86  	faWithSourceAppAndTargetApp               = fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeApplication, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
    87  	faWithSourceAppAndTargetAppReverse        = fixReverseFormationAssignment(faWithSourceAppAndTargetApp)
    88  	webhookFaWithSourceAppAndTargetApp        = convertFormationAssignmentFromModel(faWithSourceAppAndTargetApp)
    89  	webhookFaWithSourceAppAndTargetAppReverse = convertFormationAssignmentFromModel(faWithSourceAppAndTargetAppReverse)
    90  
    91  	testAppTenantMappingWebhookInput            = fixAppTenantMappingWebhookInput(TestFormationID, testAppWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppTemplateWithLabels, testCustomerTenantContext, fixConvertFAFromModel(faWithSourceAppAndTargetApp), fixConvertFAFromModel(faWithSourceAppAndTargetAppReverse))
    92  	testAppNotificationReqWithTenantMappingType = &webhookclient.FormationAssignmentNotificationRequest{
    93  		Webhook:       *testGqlAppWebhook,
    94  		Object:        testAppTenantMappingWebhookInput,
    95  		CorrelationID: "",
    96  	}
    97  
    98  	applicationLabelInput = &model.LabelInput{
    99  		Key:        appTypeLabelKey,
   100  		ObjectID:   TestTarget,
   101  		ObjectType: model.ApplicationLabelableObject,
   102  	}
   103  	applicationTypeLabel = &model.Label{Value: appSubtype}
   104  	runtimeTypeLabel     = &model.Label{Value: rtmSubtype}
   105  )
   106  
   107  func Test_GenerateFormationAssignmentNotification(t *testing.T) {
   108  	ctx := context.TODO()
   109  
   110  	testNotFoundErr := apperrors.NewNotFoundError(resource.Webhook, TestTarget)
   111  	faWithInvalidTypes := fixFormationAssignmentModel(TestConfigValueRawJSON)
   112  
   113  	faWithSourceRuntimeAndTargetApp := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeApplication, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
   114  	faWithSourceRuntimeAndTargetAppReverse := fixReverseFormationAssignment(faWithSourceRuntimeAndTargetApp)
   115  
   116  	faWithSourceRuntimeCtxAndTargetApp := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeRuntimeContext, model.FormationAssignmentTypeApplication, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
   117  	faWithSourceRuntimeCtxAndTargetAppReverse := fixReverseFormationAssignment(faWithSourceRuntimeCtxAndTargetApp)
   118  
   119  	faWithSourceAppAndTargetRuntime := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntime, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
   120  	faWithSourceAppAndTargetRuntimeReverse := fixReverseFormationAssignment(faWithSourceAppAndTargetRuntime)
   121  
   122  	faWithSourceInvalidAndTargetRuntime := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeRuntime, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
   123  	faWithSourceInvalidAndTargetRtmCtx := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeRuntimeContext, model.FormationAssignmentTypeRuntimeContext, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
   124  
   125  	faWithSourceAppCtxAndTargetRtmCtx := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntimeContext, string(model.ReadyAssignmentState), TestConfigValueRawJSON)
   126  	faWithSourceAppCtxAndTargetRtmCtxReverse := fixReverseFormationAssignment(faWithSourceAppCtxAndTargetRtmCtx)
   127  
   128  	testGqlRuntimeWebhook := &graphql.Webhook{
   129  		ID:   testRuntimeWebhook.ID,
   130  		Type: graphql.WebhookType(testRuntimeWebhook.Type),
   131  	}
   132  
   133  	testCustomerTenantContextWithPath := &webhook.CustomerTenantContext{
   134  		CustomerID: TntParentID,
   135  		AccountID:  nil,
   136  		Path:       str.Ptr(TestTenantID),
   137  	}
   138  
   139  	testAppTenantMappingWebhookInputWithTenantPath := fixAppTenantMappingWebhookInput(TestFormationID, testAppWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppTemplateWithLabels, testCustomerTenantContextWithPath, fixConvertFAFromModel(faWithSourceAppAndTargetApp), fixConvertFAFromModel(faWithSourceAppAndTargetAppReverse))
   140  	testAppNotificationReqWithTenantMappingTypeWithTenantPath := &webhookclient.FormationAssignmentNotificationRequest{
   141  		Webhook:       *testGqlAppWebhook,
   142  		Object:        testAppTenantMappingWebhookInputWithTenantPath,
   143  		CorrelationID: "",
   144  	}
   145  
   146  	testFormationConfigurationChangeInputWithSourceRuntimeAndTargetApp := fixFormationConfigurationChangeInput(TestFormationID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, testCustomerTenantContext, fixConvertFAFromModel(faWithSourceRuntimeAndTargetApp), fixConvertFAFromModel(faWithSourceRuntimeAndTargetAppReverse))
   147  	testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceRuntimeAndTargetApp := &webhookclient.FormationAssignmentNotificationRequest{
   148  		Webhook:       *testGqlAppWebhook,
   149  		Object:        testFormationConfigurationChangeInputWithSourceRuntimeAndTargetApp,
   150  		CorrelationID: "",
   151  	}
   152  
   153  	testFormationConfigurationChangeInputWithSourceRtmCtxAndTargetApp := fixFormationConfigurationChangeInput(TestFormationID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, testCustomerTenantContext, fixConvertFAFromModel(faWithSourceRuntimeCtxAndTargetApp), fixConvertFAFromModel(faWithSourceRuntimeCtxAndTargetAppReverse))
   154  	testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceRtmCtxAndTargetApp := &webhookclient.FormationAssignmentNotificationRequest{
   155  		Webhook:       *testGqlAppWebhook,
   156  		Object:        testFormationConfigurationChangeInputWithSourceRtmCtxAndTargetApp,
   157  		CorrelationID: "",
   158  	}
   159  
   160  	testFormationConfigurationChangeInputWithSourceAppAndTargetRuntime := fixFormationConfigurationChangeInput(TestFormationID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, nil, testCustomerTenantContext, fixConvertFAFromModel(faWithSourceAppAndTargetRuntime), fixConvertFAFromModel(faWithSourceAppAndTargetRuntimeReverse))
   161  	testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceAppAndTargetRuntime := &webhookclient.FormationAssignmentNotificationRequest{
   162  		Webhook:       *testGqlRuntimeWebhook,
   163  		Object:        testFormationConfigurationChangeInputWithSourceAppAndTargetRuntime,
   164  		CorrelationID: "",
   165  	}
   166  
   167  	testFormationConfigurationChangeInputWithSourceAppAndTargetRtmCtx := fixFormationConfigurationChangeInput(TestFormationID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, testCustomerTenantContext, fixConvertFAFromModel(faWithSourceAppCtxAndTargetRtmCtx), fixConvertFAFromModel(faWithSourceAppCtxAndTargetRtmCtxReverse))
   168  	testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceAppAndTargetRtmCtx := &webhookclient.FormationAssignmentNotificationRequest{
   169  		Webhook:       *testGqlRuntimeWebhook,
   170  		Object:        testFormationConfigurationChangeInputWithSourceAppAndTargetRtmCtx,
   171  		CorrelationID: "",
   172  	}
   173  
   174  	formation := &model.Formation{FormationTemplateID: TestFormationTemplateID}
   175  	details := &formationconstraint.GenerateFormationAssignmentNotificationOperationDetails{}
   176  
   177  	var emptyRuntimeCtx *webhook.RuntimeContextWithLabels
   178  	gaTenantObject := fixModelBusinessTenantMappingWithType(tnt.Account)
   179  	rgTenantObject := fixModelBusinessTenantMappingWithType(tnt.ResourceGroup)
   180  
   181  	testCases := []struct {
   182  		name                    string
   183  		formationAssignment     *model.FormationAssignment
   184  		formationOperation      model.FormationOperation
   185  		webhookRepo             func() *automock.WebhookRepository
   186  		webhookDataInputBuilder func() *databuilderautomock.DataInputBuilder
   187  		formationAssignmentRepo func() *automock.FormationAssignmentRepository
   188  		formationRepo           func() *automock.FormationRepository
   189  		notificationBuilder     func() *automock.NotificationBuilder
   190  		tenantRepo              func() *automock.TenantRepository
   191  		expectedNotification    *webhookclient.FormationAssignmentNotificationRequest
   192  		expectedErrMsg          string
   193  	}{
   194  		{
   195  			name: "Error when formation assignment type is invalid",
   196  			formationRepo: func() *automock.FormationRepository {
   197  				repo := &automock.FormationRepository{}
   198  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(nil, nil).Once()
   199  				return repo
   200  			},
   201  			formationAssignment: faWithInvalidTypes,
   202  			formationOperation:  model.AssignFormation,
   203  			tenantRepo: func() *automock.TenantRepository {
   204  				repo := &automock.TenantRepository{}
   205  				repo.On("Get", emptyCtx, faWithInvalidTypes.TenantID).Return(gaTenantObject, nil)
   206  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithInvalidTypes.TenantID).Return(TntParentID, nil)
   207  				return repo
   208  			},
   209  			expectedErrMsg: "Unknown formation assignment type:",
   210  		},
   211  		// application formation assignment notifications with source application
   212  		{
   213  			name:                "Successfully generate application notification when source type is application and tenant is global account",
   214  			formationAssignment: faWithSourceAppAndTargetApp,
   215  			formationOperation:  model.AssignFormation,
   216  			tenantRepo: func() *automock.TenantRepository {
   217  				repo := &automock.TenantRepository{}
   218  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   219  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   220  				return repo
   221  			},
   222  			webhookRepo: func() *automock.WebhookRepository {
   223  				webhookRepo := &automock.WebhookRepository{}
   224  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(testAppWebhook, nil).Once()
   225  				return webhookRepo
   226  			},
   227  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   228  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   229  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   230  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   231  				return webhookDataInputBuilder
   232  			},
   233  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   234  				faRepo := &automock.FormationAssignmentRepository{}
   235  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   236  				return faRepo
   237  			},
   238  			formationRepo: func() *automock.FormationRepository {
   239  				repo := &automock.FormationRepository{}
   240  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   241  				return repo
   242  			},
   243  			notificationBuilder: func() *automock.NotificationBuilder {
   244  				notificationsBuilder := &automock.NotificationBuilder{}
   245  
   246  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   247  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(testAppNotificationReqWithTenantMappingType, nil).Once()
   248  
   249  				return notificationsBuilder
   250  			},
   251  			expectedNotification: testAppNotificationReqWithTenantMappingType,
   252  		},
   253  		{
   254  			name:                "Successfully generate application notification when source type is application and tenant is resource group",
   255  			formationAssignment: faWithSourceAppAndTargetApp,
   256  			formationOperation:  model.AssignFormation,
   257  			tenantRepo: func() *automock.TenantRepository {
   258  				repo := &automock.TenantRepository{}
   259  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(rgTenantObject, nil)
   260  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   261  				return repo
   262  			},
   263  			webhookRepo: func() *automock.WebhookRepository {
   264  				webhookRepo := &automock.WebhookRepository{}
   265  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(testAppWebhook, nil).Once()
   266  				return webhookRepo
   267  			},
   268  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   269  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   270  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   271  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   272  				return webhookDataInputBuilder
   273  			},
   274  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   275  				faRepo := &automock.FormationAssignmentRepository{}
   276  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   277  				return faRepo
   278  			},
   279  			formationRepo: func() *automock.FormationRepository {
   280  				repo := &automock.FormationRepository{}
   281  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   282  				return repo
   283  			},
   284  			notificationBuilder: func() *automock.NotificationBuilder {
   285  				notificationsBuilder := &automock.NotificationBuilder{}
   286  
   287  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContextWithPath, TestTenantID).Return(details, nil).Once()
   288  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(testAppNotificationReqWithTenantMappingTypeWithTenantPath, nil).Once()
   289  
   290  				return notificationsBuilder
   291  			},
   292  			expectedNotification: testAppNotificationReqWithTenantMappingTypeWithTenantPath,
   293  		},
   294  		{
   295  			name:                "Success when application webhook is not found",
   296  			formationAssignment: faWithSourceAppAndTargetApp,
   297  			formationOperation:  model.AssignFormation,
   298  			tenantRepo: func() *automock.TenantRepository {
   299  				repo := &automock.TenantRepository{}
   300  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   301  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   302  				return repo
   303  			},
   304  			webhookRepo: func() *automock.WebhookRepository {
   305  				webhookRepo := &automock.WebhookRepository{}
   306  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(nil, testNotFoundErr).Once()
   307  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testAppTemplateID, model.ApplicationTemplateWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(nil, testNotFoundErr).Once()
   308  				return webhookRepo
   309  			},
   310  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   311  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   312  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   313  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   314  				return webhookDataInputBuilder
   315  			},
   316  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   317  				faRepo := &automock.FormationAssignmentRepository{}
   318  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   319  				return faRepo
   320  			},
   321  			formationRepo: func() *automock.FormationRepository {
   322  				repo := &automock.FormationRepository{}
   323  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   324  				return repo
   325  			},
   326  			notificationBuilder: func() *automock.NotificationBuilder {
   327  				notificationsBuilder := &automock.NotificationBuilder{}
   328  
   329  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   330  
   331  				return notificationsBuilder
   332  			},
   333  		},
   334  		{
   335  			name:                "Error when getting formation by ID",
   336  			formationAssignment: faWithSourceAppAndTargetApp,
   337  			formationOperation:  model.AssignFormation,
   338  			tenantRepo: func() *automock.TenantRepository {
   339  				repo := &automock.TenantRepository{}
   340  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   341  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   342  				return repo
   343  			},
   344  			formationRepo: func() *automock.FormationRepository {
   345  				repo := &automock.FormationRepository{}
   346  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(nil, testErr).Once()
   347  				return repo
   348  			},
   349  			expectedErrMsg: testErr.Error(),
   350  		},
   351  		{
   352  			name:                "Error when getting tenant fails",
   353  			formationAssignment: faWithSourceAppAndTargetApp,
   354  			formationOperation:  model.AssignFormation,
   355  			tenantRepo: func() *automock.TenantRepository {
   356  				repo := &automock.TenantRepository{}
   357  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(nil, testErr)
   358  				return repo
   359  			},
   360  			expectedErrMsg: testErr.Error(),
   361  		},
   362  		{
   363  			name:                "Error when getting parent customer id fails",
   364  			formationAssignment: faWithSourceAppAndTargetApp,
   365  			formationOperation:  model.AssignFormation,
   366  			tenantRepo: func() *automock.TenantRepository {
   367  				repo := &automock.TenantRepository{}
   368  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   369  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return("", testErr)
   370  				return repo
   371  			},
   372  			expectedErrMsg: testErr.Error(),
   373  		},
   374  		{
   375  			name:                "Error when getting application template webhook by ID and type",
   376  			formationAssignment: faWithSourceAppAndTargetApp,
   377  			formationOperation:  model.AssignFormation,
   378  			tenantRepo: func() *automock.TenantRepository {
   379  				repo := &automock.TenantRepository{}
   380  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   381  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   382  				return repo
   383  			},
   384  			webhookRepo: func() *automock.WebhookRepository {
   385  				webhookRepo := &automock.WebhookRepository{}
   386  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(nil, testNotFoundErr).Once()
   387  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testAppTemplateID, model.ApplicationTemplateWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(nil, testErr).Once()
   388  
   389  				return webhookRepo
   390  			},
   391  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   392  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   393  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   394  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   395  				return webhookDataInputBuilder
   396  			},
   397  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   398  				faRepo := &automock.FormationAssignmentRepository{}
   399  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   400  				return faRepo
   401  			},
   402  			formationRepo: func() *automock.FormationRepository {
   403  				repo := &automock.FormationRepository{}
   404  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   405  				return repo
   406  			},
   407  			notificationBuilder: func() *automock.NotificationBuilder {
   408  				notificationsBuilder := &automock.NotificationBuilder{}
   409  
   410  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   411  
   412  				return notificationsBuilder
   413  			},
   414  			expectedErrMsg: fmt.Sprintf("while listing %q webhooks for application template with ID: %q on behalf of application with ID: %q", model.WebhookTypeApplicationTenantMapping, testAppTemplateID, TestTarget),
   415  		},
   416  		{
   417  			name:                "Error when preparing app and app template with labels for source type application",
   418  			formationAssignment: faWithSourceAppAndTargetApp,
   419  			formationOperation:  model.AssignFormation,
   420  			tenantRepo: func() *automock.TenantRepository {
   421  				repo := &automock.TenantRepository{}
   422  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   423  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   424  				return repo
   425  			},
   426  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   427  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   428  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(nil, nil, testErr).Once()
   429  				return webhookDataInputBuilder
   430  			},
   431  			formationRepo: func() *automock.FormationRepository {
   432  				repo := &automock.FormationRepository{}
   433  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   434  				return repo
   435  			},
   436  			expectedErrMsg: testErr.Error(),
   437  		},
   438  		{
   439  			name:                "Error when preparing reverse app and app template with labels for source type application",
   440  			formationAssignment: faWithSourceAppAndTargetApp,
   441  			formationOperation:  model.AssignFormation,
   442  			tenantRepo: func() *automock.TenantRepository {
   443  				repo := &automock.TenantRepository{}
   444  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   445  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   446  				return repo
   447  			},
   448  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   449  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   450  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   451  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(nil, nil, testErr).Once()
   452  				return webhookDataInputBuilder
   453  			},
   454  			formationRepo: func() *automock.FormationRepository {
   455  				repo := &automock.FormationRepository{}
   456  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   457  				return repo
   458  			},
   459  			expectedErrMsg: testErr.Error(),
   460  		},
   461  		{
   462  			name:                "Error when getting reverse formation assignment by source and target for source type application",
   463  			formationAssignment: faWithSourceAppAndTargetApp,
   464  			formationOperation:  model.AssignFormation,
   465  			tenantRepo: func() *automock.TenantRepository {
   466  				repo := &automock.TenantRepository{}
   467  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   468  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   469  				return repo
   470  			},
   471  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   472  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   473  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   474  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   475  				return webhookDataInputBuilder
   476  			},
   477  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   478  				faRepo := &automock.FormationAssignmentRepository{}
   479  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, testErr).Once()
   480  				return faRepo
   481  			},
   482  			formationRepo: func() *automock.FormationRepository {
   483  				repo := &automock.FormationRepository{}
   484  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   485  				return repo
   486  			},
   487  			expectedErrMsg: testErr.Error(),
   488  		},
   489  		{
   490  			name:                "Error when preparing details",
   491  			formationAssignment: faWithSourceAppAndTargetApp,
   492  			formationOperation:  model.AssignFormation,
   493  			tenantRepo: func() *automock.TenantRepository {
   494  				repo := &automock.TenantRepository{}
   495  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   496  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   497  				return repo
   498  			},
   499  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   500  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   501  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   502  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   503  				return webhookDataInputBuilder
   504  			},
   505  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   506  				faRepo := &automock.FormationAssignmentRepository{}
   507  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   508  				return faRepo
   509  			},
   510  			formationRepo: func() *automock.FormationRepository {
   511  				repo := &automock.FormationRepository{}
   512  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   513  				return repo
   514  			},
   515  			notificationBuilder: func() *automock.NotificationBuilder {
   516  				notificationsBuilder := &automock.NotificationBuilder{}
   517  
   518  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContext, TestTenantID).Return(nil, testErr).Once()
   519  
   520  				return notificationsBuilder
   521  			},
   522  			expectedErrMsg: testErr.Error(),
   523  		},
   524  		{
   525  			name:                "Error while building notification request",
   526  			formationAssignment: faWithSourceAppAndTargetApp,
   527  			formationOperation:  model.AssignFormation,
   528  			tenantRepo: func() *automock.TenantRepository {
   529  				repo := &automock.TenantRepository{}
   530  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   531  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   532  				return repo
   533  			},
   534  			webhookRepo: func() *automock.WebhookRepository {
   535  				webhookRepo := &automock.WebhookRepository{}
   536  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(testAppWebhook, nil).Once()
   537  				return webhookRepo
   538  			},
   539  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   540  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   541  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   542  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   543  				return webhookDataInputBuilder
   544  			},
   545  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   546  				faRepo := &automock.FormationAssignmentRepository{}
   547  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   548  				return faRepo
   549  			},
   550  			formationRepo: func() *automock.FormationRepository {
   551  				repo := &automock.FormationRepository{}
   552  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   553  				return repo
   554  			},
   555  			notificationBuilder: func() *automock.NotificationBuilder {
   556  				notificationsBuilder := &automock.NotificationBuilder{}
   557  
   558  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   559  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(nil, testErr).Once()
   560  
   561  				return notificationsBuilder
   562  			},
   563  			expectedErrMsg: testErr.Error(),
   564  		},
   565  		{
   566  			name:                "Error when getting application webhook by ID and type",
   567  			formationAssignment: faWithSourceAppAndTargetApp,
   568  			formationOperation:  model.AssignFormation,
   569  			tenantRepo: func() *automock.TenantRepository {
   570  				repo := &automock.TenantRepository{}
   571  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(gaTenantObject, nil)
   572  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetApp.TenantID).Return(TntParentID, nil)
   573  				return repo
   574  			},
   575  			webhookRepo: func() *automock.WebhookRepository {
   576  				webhookRepo := &automock.WebhookRepository{}
   577  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeApplicationTenantMapping).Return(nil, testErr).Once()
   578  				return webhookRepo
   579  			},
   580  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   581  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   582  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   583  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   584  				return webhookDataInputBuilder
   585  			},
   586  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   587  				faRepo := &automock.FormationAssignmentRepository{}
   588  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetAppReverse, nil).Once()
   589  				return faRepo
   590  			},
   591  			formationRepo: func() *automock.FormationRepository {
   592  				repo := &automock.FormationRepository{}
   593  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   594  				return repo
   595  			},
   596  			notificationBuilder: func() *automock.NotificationBuilder {
   597  				notificationsBuilder := &automock.NotificationBuilder{}
   598  
   599  				notificationsBuilder.On("PrepareDetailsForApplicationTenantMappingNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testAppTemplateWithLabels, testAppWithLabels, webhookFaWithSourceAppAndTargetApp, webhookFaWithSourceAppAndTargetAppReverse, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   600  
   601  				return notificationsBuilder
   602  			},
   603  			expectedErrMsg: testErr.Error(),
   604  		},
   605  		// application formation assignment notifications with source runtime
   606  		{
   607  			name:                "Successfully generate application notification when source type is runtime",
   608  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   609  			formationOperation:  model.AssignFormation,
   610  			tenantRepo: func() *automock.TenantRepository {
   611  				repo := &automock.TenantRepository{}
   612  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   613  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   614  				return repo
   615  			},
   616  			webhookRepo: func() *automock.WebhookRepository {
   617  				webhookRepo := &automock.WebhookRepository{}
   618  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(testAppWebhook, nil).Once()
   619  				return webhookRepo
   620  			},
   621  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   622  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   623  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   624  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeWithLabels, nil).Once()
   625  				return webhookDataInputBuilder
   626  			},
   627  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   628  				faRepo := &automock.FormationAssignmentRepository{}
   629  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeAndTargetAppReverse, nil).Once()
   630  				return faRepo
   631  			},
   632  			formationRepo: func() *automock.FormationRepository {
   633  				repo := &automock.FormationRepository{}
   634  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   635  				return repo
   636  			},
   637  			notificationBuilder: func() *automock.NotificationBuilder {
   638  				notificationsBuilder := &automock.NotificationBuilder{}
   639  
   640  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   641  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceRuntimeAndTargetApp, nil).Once()
   642  
   643  				return notificationsBuilder
   644  			},
   645  			expectedNotification: testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceRuntimeAndTargetApp,
   646  		},
   647  		{
   648  			name:                "Error when getting tenant fails",
   649  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   650  			formationOperation:  model.AssignFormation,
   651  			tenantRepo: func() *automock.TenantRepository {
   652  				repo := &automock.TenantRepository{}
   653  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(nil, testErr)
   654  				return repo
   655  			},
   656  			expectedErrMsg: testErr.Error(),
   657  		},
   658  		{
   659  			name:                "Error when getting parent customer id fails",
   660  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   661  			formationOperation:  model.AssignFormation,
   662  			tenantRepo: func() *automock.TenantRepository {
   663  				repo := &automock.TenantRepository{}
   664  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   665  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return("", testErr)
   666  				return repo
   667  			},
   668  			expectedErrMsg: testErr.Error(),
   669  		},
   670  		{
   671  			name:                "Error when preparing app and app template with labels for source type runtime",
   672  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   673  			formationOperation:  model.AssignFormation,
   674  			tenantRepo: func() *automock.TenantRepository {
   675  				repo := &automock.TenantRepository{}
   676  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   677  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   678  				return repo
   679  			},
   680  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   681  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   682  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(nil, nil, testErr).Once()
   683  				return webhookDataInputBuilder
   684  			},
   685  			formationRepo: func() *automock.FormationRepository {
   686  				repo := &automock.FormationRepository{}
   687  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   688  				return repo
   689  			},
   690  			expectedErrMsg: testErr.Error(),
   691  		},
   692  		{
   693  			name:                "Error when preparing runtime and runtime context with labels for source type runtime",
   694  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   695  			formationOperation:  model.AssignFormation,
   696  			tenantRepo: func() *automock.TenantRepository {
   697  				repo := &automock.TenantRepository{}
   698  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   699  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   700  				return repo
   701  			},
   702  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   703  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   704  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   705  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(nil, testErr).Once()
   706  				return webhookDataInputBuilder
   707  			},
   708  			formationRepo: func() *automock.FormationRepository {
   709  				repo := &automock.FormationRepository{}
   710  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   711  				return repo
   712  			},
   713  			expectedErrMsg: testErr.Error(),
   714  		},
   715  		{
   716  			name:                "Error when getting reverse formation assignment by source and target for source type runtime",
   717  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   718  			formationOperation:  model.AssignFormation,
   719  			tenantRepo: func() *automock.TenantRepository {
   720  				repo := &automock.TenantRepository{}
   721  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   722  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   723  				return repo
   724  			},
   725  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   726  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   727  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   728  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeWithLabels, nil).Once()
   729  				return webhookDataInputBuilder
   730  			},
   731  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   732  				faRepo := &automock.FormationAssignmentRepository{}
   733  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, testErr).Once()
   734  				return faRepo
   735  			},
   736  			formationRepo: func() *automock.FormationRepository {
   737  				repo := &automock.FormationRepository{}
   738  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   739  				return repo
   740  			},
   741  			expectedErrMsg: testErr.Error(),
   742  		},
   743  		{
   744  			name:                "Error when preparing details for source type runtime",
   745  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   746  			formationOperation:  model.AssignFormation,
   747  			tenantRepo: func() *automock.TenantRepository {
   748  				repo := &automock.TenantRepository{}
   749  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   750  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   751  				return repo
   752  			},
   753  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   754  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   755  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   756  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeWithLabels, nil).Once()
   757  				return webhookDataInputBuilder
   758  			},
   759  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   760  				faRepo := &automock.FormationAssignmentRepository{}
   761  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeAndTargetAppReverse, nil).Once()
   762  				return faRepo
   763  			},
   764  			formationRepo: func() *automock.FormationRepository {
   765  				repo := &automock.FormationRepository{}
   766  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   767  				return repo
   768  			},
   769  			notificationBuilder: func() *automock.NotificationBuilder {
   770  				notificationsBuilder := &automock.NotificationBuilder{}
   771  
   772  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(nil, testErr).Once()
   773  
   774  				return notificationsBuilder
   775  			},
   776  			expectedErrMsg: testErr.Error(),
   777  		},
   778  		{
   779  			name:                "Success when getting application webhook return not found error",
   780  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   781  			formationOperation:  model.AssignFormation,
   782  			tenantRepo: func() *automock.TenantRepository {
   783  				repo := &automock.TenantRepository{}
   784  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   785  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   786  				return repo
   787  			},
   788  			webhookRepo: func() *automock.WebhookRepository {
   789  				webhookRepo := &automock.WebhookRepository{}
   790  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testNotFoundErr).Once()
   791  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testAppTemplateID, model.ApplicationTemplateWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testNotFoundErr).Once()
   792  				return webhookRepo
   793  			},
   794  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   795  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   796  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   797  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeWithLabels, nil).Once()
   798  				return webhookDataInputBuilder
   799  			},
   800  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   801  				faRepo := &automock.FormationAssignmentRepository{}
   802  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeAndTargetAppReverse, nil).Once()
   803  				return faRepo
   804  			},
   805  			formationRepo: func() *automock.FormationRepository {
   806  				repo := &automock.FormationRepository{}
   807  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   808  				return repo
   809  			},
   810  			notificationBuilder: func() *automock.NotificationBuilder {
   811  				notificationsBuilder := &automock.NotificationBuilder{}
   812  
   813  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   814  
   815  				return notificationsBuilder
   816  			},
   817  		},
   818  		{
   819  			name:                "Error when getting application webhook by ID and type",
   820  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   821  			formationOperation:  model.AssignFormation,
   822  			tenantRepo: func() *automock.TenantRepository {
   823  				repo := &automock.TenantRepository{}
   824  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   825  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   826  				return repo
   827  			},
   828  			webhookRepo: func() *automock.WebhookRepository {
   829  				webhookRepo := &automock.WebhookRepository{}
   830  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testErr).Once()
   831  				return webhookRepo
   832  			},
   833  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   834  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   835  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   836  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeWithLabels, nil).Once()
   837  				return webhookDataInputBuilder
   838  			},
   839  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   840  				faRepo := &automock.FormationAssignmentRepository{}
   841  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeAndTargetAppReverse, nil).Once()
   842  				return faRepo
   843  			},
   844  			formationRepo: func() *automock.FormationRepository {
   845  				repo := &automock.FormationRepository{}
   846  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   847  				return repo
   848  			},
   849  			notificationBuilder: func() *automock.NotificationBuilder {
   850  				notificationsBuilder := &automock.NotificationBuilder{}
   851  
   852  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   853  
   854  				return notificationsBuilder
   855  			},
   856  			expectedErrMsg: testErr.Error(),
   857  		},
   858  		{
   859  			name:                "Error when building notification request for source type runtime",
   860  			formationAssignment: faWithSourceRuntimeAndTargetApp,
   861  			formationOperation:  model.AssignFormation,
   862  			tenantRepo: func() *automock.TenantRepository {
   863  				repo := &automock.TenantRepository{}
   864  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
   865  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
   866  				return repo
   867  			},
   868  			webhookRepo: func() *automock.WebhookRepository {
   869  				webhookRepo := &automock.WebhookRepository{}
   870  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(testAppWebhook, nil).Once()
   871  				return webhookRepo
   872  			},
   873  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   874  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   875  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   876  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeWithLabels, nil).Once()
   877  				return webhookDataInputBuilder
   878  			},
   879  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   880  				faRepo := &automock.FormationAssignmentRepository{}
   881  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeAndTargetAppReverse, nil).Once()
   882  				return faRepo
   883  			},
   884  			formationRepo: func() *automock.FormationRepository {
   885  				repo := &automock.FormationRepository{}
   886  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   887  				return repo
   888  			},
   889  			notificationBuilder: func() *automock.NotificationBuilder {
   890  				notificationsBuilder := &automock.NotificationBuilder{}
   891  
   892  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   893  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(nil, testErr).Once()
   894  
   895  				return notificationsBuilder
   896  			},
   897  			expectedErrMsg: testErr.Error(),
   898  		},
   899  		// application formation assignment notifications with source runtime context
   900  		{
   901  			name:                "Successfully generate application notification when source type is runtime context",
   902  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
   903  			formationOperation:  model.AssignFormation,
   904  			tenantRepo: func() *automock.TenantRepository {
   905  				repo := &automock.TenantRepository{}
   906  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
   907  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
   908  				return repo
   909  			},
   910  			webhookRepo: func() *automock.WebhookRepository {
   911  				webhookRepo := &automock.WebhookRepository{}
   912  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(testAppWebhook, nil).Once()
   913  				return webhookRepo
   914  			},
   915  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   916  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   917  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
   918  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
   919  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
   920  				return webhookDataInputBuilder
   921  			},
   922  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   923  				faRepo := &automock.FormationAssignmentRepository{}
   924  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeCtxAndTargetAppReverse, nil).Once()
   925  				return faRepo
   926  			},
   927  			formationRepo: func() *automock.FormationRepository {
   928  				repo := &automock.FormationRepository{}
   929  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   930  				return repo
   931  			},
   932  			notificationBuilder: func() *automock.NotificationBuilder {
   933  				notificationsBuilder := &automock.NotificationBuilder{}
   934  
   935  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
   936  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceRtmCtxAndTargetApp, nil).Once()
   937  
   938  				return notificationsBuilder
   939  			},
   940  			expectedNotification: testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceRtmCtxAndTargetApp,
   941  		},
   942  		{
   943  			name:                "Error when getting tenant fails",
   944  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
   945  			formationOperation:  model.AssignFormation,
   946  			tenantRepo: func() *automock.TenantRepository {
   947  				repo := &automock.TenantRepository{}
   948  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(nil, testErr)
   949  				return repo
   950  			},
   951  			expectedErrMsg: testErr.Error(),
   952  		},
   953  		{
   954  			name:                "Error when getting parent customer id fails",
   955  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
   956  			formationOperation:  model.AssignFormation,
   957  			tenantRepo: func() *automock.TenantRepository {
   958  				repo := &automock.TenantRepository{}
   959  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
   960  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return("", testErr)
   961  				return repo
   962  			},
   963  			expectedErrMsg: testErr.Error(),
   964  		},
   965  		{
   966  			name:                "Error when preparing app and app template with labels for source type runtime context",
   967  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
   968  			formationOperation:  model.AssignFormation,
   969  			tenantRepo: func() *automock.TenantRepository {
   970  				repo := &automock.TenantRepository{}
   971  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
   972  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
   973  				return repo
   974  			},
   975  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   976  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   977  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(nil, nil, testErr).Once()
   978  				return webhookDataInputBuilder
   979  			},
   980  			formationRepo: func() *automock.FormationRepository {
   981  				repo := &automock.FormationRepository{}
   982  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
   983  				return repo
   984  			},
   985  			expectedErrMsg: testErr.Error(),
   986  		},
   987  		{
   988  			name:                "Error when preparing runtime context with labels for source type runtime context",
   989  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
   990  			formationOperation:  model.AssignFormation,
   991  			tenantRepo: func() *automock.TenantRepository {
   992  				repo := &automock.TenantRepository{}
   993  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
   994  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
   995  				return repo
   996  			},
   997  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
   998  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
   999  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1000  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(nil, testErr).Once()
  1001  				return webhookDataInputBuilder
  1002  			},
  1003  			formationRepo: func() *automock.FormationRepository {
  1004  				repo := &automock.FormationRepository{}
  1005  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1006  				return repo
  1007  			},
  1008  			expectedErrMsg: testErr.Error(),
  1009  		},
  1010  		{
  1011  			name:                "Error when preparing runtime with labels for source type runtime context",
  1012  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
  1013  			formationOperation:  model.AssignFormation,
  1014  			tenantRepo: func() *automock.TenantRepository {
  1015  				repo := &automock.TenantRepository{}
  1016  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1017  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
  1018  				return repo
  1019  			},
  1020  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1021  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1022  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1023  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
  1024  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(nil, testErr).Once()
  1025  				return webhookDataInputBuilder
  1026  			},
  1027  			formationRepo: func() *automock.FormationRepository {
  1028  				repo := &automock.FormationRepository{}
  1029  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1030  				return repo
  1031  			},
  1032  			expectedErrMsg: testErr.Error(),
  1033  		},
  1034  		{
  1035  			name:                "Error when getting reverse formation assignment by source and target for source type runtime context",
  1036  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
  1037  			formationOperation:  model.AssignFormation,
  1038  			tenantRepo: func() *automock.TenantRepository {
  1039  				repo := &automock.TenantRepository{}
  1040  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1041  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
  1042  				return repo
  1043  			},
  1044  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1045  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1046  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1047  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
  1048  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1049  				return webhookDataInputBuilder
  1050  			},
  1051  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1052  				faRepo := &automock.FormationAssignmentRepository{}
  1053  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, testErr).Once()
  1054  				return faRepo
  1055  			},
  1056  			formationRepo: func() *automock.FormationRepository {
  1057  				repo := &automock.FormationRepository{}
  1058  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1059  				return repo
  1060  			},
  1061  			expectedErrMsg: testErr.Error(),
  1062  		},
  1063  		{
  1064  			name:                "Error when preparing details for source type runtime context",
  1065  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
  1066  			formationOperation:  model.AssignFormation,
  1067  			tenantRepo: func() *automock.TenantRepository {
  1068  				repo := &automock.TenantRepository{}
  1069  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1070  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
  1071  				return repo
  1072  			},
  1073  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1074  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1075  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1076  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
  1077  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1078  				return webhookDataInputBuilder
  1079  			},
  1080  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1081  				faRepo := &automock.FormationAssignmentRepository{}
  1082  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeCtxAndTargetAppReverse, nil).Once()
  1083  				return faRepo
  1084  			},
  1085  			formationRepo: func() *automock.FormationRepository {
  1086  				repo := &automock.FormationRepository{}
  1087  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1088  				return repo
  1089  			},
  1090  			notificationBuilder: func() *automock.NotificationBuilder {
  1091  				notificationsBuilder := &automock.NotificationBuilder{}
  1092  
  1093  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(nil, testErr).Once()
  1094  
  1095  				return notificationsBuilder
  1096  			},
  1097  			expectedErrMsg: testErr.Error(),
  1098  		},
  1099  		{
  1100  			name:                "Success when getting application webhook by ID and type return not found error",
  1101  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
  1102  			formationOperation:  model.AssignFormation,
  1103  			tenantRepo: func() *automock.TenantRepository {
  1104  				repo := &automock.TenantRepository{}
  1105  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1106  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
  1107  				return repo
  1108  			},
  1109  			webhookRepo: func() *automock.WebhookRepository {
  1110  				webhookRepo := &automock.WebhookRepository{}
  1111  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testNotFoundErr).Once()
  1112  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testAppTemplateID, model.ApplicationTemplateWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testNotFoundErr).Once()
  1113  
  1114  				return webhookRepo
  1115  			},
  1116  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1117  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1118  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1119  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
  1120  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1121  				return webhookDataInputBuilder
  1122  			},
  1123  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1124  				faRepo := &automock.FormationAssignmentRepository{}
  1125  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeCtxAndTargetAppReverse, nil).Once()
  1126  				return faRepo
  1127  			},
  1128  			formationRepo: func() *automock.FormationRepository {
  1129  				repo := &automock.FormationRepository{}
  1130  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1131  				return repo
  1132  			},
  1133  			notificationBuilder: func() *automock.NotificationBuilder {
  1134  				notificationsBuilder := &automock.NotificationBuilder{}
  1135  
  1136  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1137  
  1138  				return notificationsBuilder
  1139  			},
  1140  		},
  1141  		{
  1142  			name:                "Error when getting application webhook by ID and type",
  1143  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
  1144  			formationOperation:  model.AssignFormation,
  1145  			tenantRepo: func() *automock.TenantRepository {
  1146  				repo := &automock.TenantRepository{}
  1147  				repo.On("Get", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1148  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeCtxAndTargetApp.TenantID).Return(TntParentID, nil)
  1149  				return repo
  1150  			},
  1151  			webhookRepo: func() *automock.WebhookRepository {
  1152  				webhookRepo := &automock.WebhookRepository{}
  1153  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testErr).Once()
  1154  				return webhookRepo
  1155  			},
  1156  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1157  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1158  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1159  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
  1160  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1161  				return webhookDataInputBuilder
  1162  			},
  1163  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1164  				faRepo := &automock.FormationAssignmentRepository{}
  1165  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeCtxAndTargetAppReverse, nil).Once()
  1166  				return faRepo
  1167  			},
  1168  			formationRepo: func() *automock.FormationRepository {
  1169  				repo := &automock.FormationRepository{}
  1170  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1171  				return repo
  1172  			},
  1173  			notificationBuilder: func() *automock.NotificationBuilder {
  1174  				notificationsBuilder := &automock.NotificationBuilder{}
  1175  
  1176  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1177  
  1178  				return notificationsBuilder
  1179  			},
  1180  			expectedErrMsg: testErr.Error(),
  1181  		},
  1182  		{
  1183  			name:                "Error when building notification request for source type runtime context",
  1184  			formationAssignment: faWithSourceRuntimeCtxAndTargetApp,
  1185  			formationOperation:  model.AssignFormation,
  1186  			tenantRepo: func() *automock.TenantRepository {
  1187  				repo := &automock.TenantRepository{}
  1188  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1189  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
  1190  				return repo
  1191  			},
  1192  			webhookRepo: func() *automock.WebhookRepository {
  1193  				webhookRepo := &automock.WebhookRepository{}
  1194  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.ApplicationWebhookReference, model.WebhookTypeConfigurationChanged).Return(testAppWebhook, nil).Once()
  1195  				return webhookRepo
  1196  			},
  1197  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1198  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1199  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1200  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestSource).Return(testRuntimeCtxWithLabels, nil).Once()
  1201  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1202  				return webhookDataInputBuilder
  1203  			},
  1204  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1205  				faRepo := &automock.FormationAssignmentRepository{}
  1206  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceRuntimeCtxAndTargetAppReverse, nil).Once()
  1207  				return faRepo
  1208  			},
  1209  			formationRepo: func() *automock.FormationRepository {
  1210  				repo := &automock.FormationRepository{}
  1211  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1212  				return repo
  1213  			},
  1214  			notificationBuilder: func() *automock.NotificationBuilder {
  1215  				notificationsBuilder := &automock.NotificationBuilder{}
  1216  
  1217  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetApp), convertFormationAssignmentFromModel(faWithSourceRuntimeCtxAndTargetAppReverse), model.ApplicationResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1218  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testAppWebhook).Return(nil, testErr).Once()
  1219  
  1220  				return notificationsBuilder
  1221  			},
  1222  			expectedErrMsg: testErr.Error(),
  1223  		},
  1224  		// runtime formation assignment notifications with source application
  1225  		{
  1226  			name:                "Successfully generate runtime notification when source type is application",
  1227  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1228  			formationOperation:  model.AssignFormation,
  1229  			tenantRepo: func() *automock.TenantRepository {
  1230  				repo := &automock.TenantRepository{}
  1231  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1232  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1233  				return repo
  1234  			},
  1235  			webhookRepo: func() *automock.WebhookRepository {
  1236  				webhookRepo := &automock.WebhookRepository{}
  1237  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1238  				return webhookRepo
  1239  			},
  1240  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1241  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1242  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1243  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeWithLabels, nil).Once()
  1244  				return webhookDataInputBuilder
  1245  			},
  1246  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1247  				faRepo := &automock.FormationAssignmentRepository{}
  1248  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetRuntimeReverse, nil).Once()
  1249  				return faRepo
  1250  			},
  1251  			formationRepo: func() *automock.FormationRepository {
  1252  				repo := &automock.FormationRepository{}
  1253  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1254  				return repo
  1255  			},
  1256  			notificationBuilder: func() *automock.NotificationBuilder {
  1257  				notificationsBuilder := &automock.NotificationBuilder{}
  1258  
  1259  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceAppAndTargetRuntime), convertFormationAssignmentFromModel(faWithSourceAppAndTargetRuntimeReverse), model.RuntimeResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1260  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testRuntimeWebhook).Return(testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceAppAndTargetRuntime, nil).Once()
  1261  
  1262  				return notificationsBuilder
  1263  			},
  1264  			expectedNotification: testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceAppAndTargetRuntime,
  1265  		},
  1266  		{
  1267  			name:                "Success when runtime webhook is not found",
  1268  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1269  			formationOperation:  model.AssignFormation,
  1270  			tenantRepo: func() *automock.TenantRepository {
  1271  				repo := &automock.TenantRepository{}
  1272  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1273  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1274  				return repo
  1275  			},
  1276  			webhookRepo: func() *automock.WebhookRepository {
  1277  				webhookRepo := &automock.WebhookRepository{}
  1278  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testNotFoundErr).Once()
  1279  				return webhookRepo
  1280  			},
  1281  			formationRepo: func() *automock.FormationRepository {
  1282  				repo := &automock.FormationRepository{}
  1283  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1284  				return repo
  1285  			},
  1286  		},
  1287  		{
  1288  			name:                "Error when getting tenant fails",
  1289  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1290  			formationOperation:  model.AssignFormation,
  1291  			tenantRepo: func() *automock.TenantRepository {
  1292  				repo := &automock.TenantRepository{}
  1293  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(nil, testErr)
  1294  				return repo
  1295  			},
  1296  			expectedErrMsg: testErr.Error(),
  1297  		},
  1298  		{
  1299  			name:                "Error when getting parent customer id fails",
  1300  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1301  			formationOperation:  model.AssignFormation,
  1302  			tenantRepo: func() *automock.TenantRepository {
  1303  				repo := &automock.TenantRepository{}
  1304  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1305  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return("", testErr)
  1306  				return repo
  1307  			},
  1308  			expectedErrMsg: testErr.Error(),
  1309  		},
  1310  		{
  1311  			name:                "Error when getting runtime webhook by ID and type for runtime target",
  1312  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1313  			formationOperation:  model.AssignFormation,
  1314  			tenantRepo: func() *automock.TenantRepository {
  1315  				repo := &automock.TenantRepository{}
  1316  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1317  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1318  				return repo
  1319  			},
  1320  			webhookRepo: func() *automock.WebhookRepository {
  1321  				webhookRepo := &automock.WebhookRepository{}
  1322  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testErr).Once()
  1323  				return webhookRepo
  1324  			},
  1325  			formationRepo: func() *automock.FormationRepository {
  1326  				repo := &automock.FormationRepository{}
  1327  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1328  				return repo
  1329  			},
  1330  			expectedErrMsg: "while getting configuration changed webhook for runtime with ID:",
  1331  		},
  1332  		{
  1333  			name:                "Error when source type is different than application for runtime target",
  1334  			formationAssignment: faWithSourceInvalidAndTargetRuntime,
  1335  			formationOperation:  model.AssignFormation,
  1336  			tenantRepo: func() *automock.TenantRepository {
  1337  				repo := &automock.TenantRepository{}
  1338  				repo.On("Get", emptyCtx, faWithSourceInvalidAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1339  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceInvalidAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1340  				return repo
  1341  			},
  1342  			webhookRepo: func() *automock.WebhookRepository {
  1343  				webhookRepo := &automock.WebhookRepository{}
  1344  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1345  				return webhookRepo
  1346  			},
  1347  			formationRepo: func() *automock.FormationRepository {
  1348  				repo := &automock.FormationRepository{}
  1349  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1350  				return repo
  1351  			},
  1352  			expectedErrMsg: fmt.Sprintf("The formation assignmet with ID: %q and target type: %q has unsupported reverse(source) type: %q", TestID, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeRuntime),
  1353  		},
  1354  		{
  1355  			name:                "Error when preparing app and app template with labels for source type application and runtime target",
  1356  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1357  			formationOperation:  model.AssignFormation,
  1358  			tenantRepo: func() *automock.TenantRepository {
  1359  				repo := &automock.TenantRepository{}
  1360  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1361  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1362  				return repo
  1363  			},
  1364  			webhookRepo: func() *automock.WebhookRepository {
  1365  				webhookRepo := &automock.WebhookRepository{}
  1366  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1367  				return webhookRepo
  1368  			},
  1369  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1370  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1371  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(nil, nil, testErr).Once()
  1372  				return webhookDataInputBuilder
  1373  			},
  1374  			formationRepo: func() *automock.FormationRepository {
  1375  				repo := &automock.FormationRepository{}
  1376  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1377  				return repo
  1378  			},
  1379  			expectedErrMsg: testErr.Error(),
  1380  		},
  1381  		{
  1382  			name:                "Error when preparing runtime with labels for source type application",
  1383  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1384  			formationOperation:  model.AssignFormation,
  1385  			tenantRepo: func() *automock.TenantRepository {
  1386  				repo := &automock.TenantRepository{}
  1387  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1388  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1389  				return repo
  1390  			},
  1391  			webhookRepo: func() *automock.WebhookRepository {
  1392  				webhookRepo := &automock.WebhookRepository{}
  1393  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1394  				return webhookRepo
  1395  			},
  1396  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1397  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1398  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1399  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestTarget).Return(nil, testErr).Once()
  1400  				return webhookDataInputBuilder
  1401  			},
  1402  			formationRepo: func() *automock.FormationRepository {
  1403  				repo := &automock.FormationRepository{}
  1404  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1405  				return repo
  1406  			},
  1407  			expectedErrMsg: testErr.Error(),
  1408  		},
  1409  		{
  1410  			name:                "Error when getting reverse FA by application source and runtime target",
  1411  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1412  			formationOperation:  model.AssignFormation,
  1413  			tenantRepo: func() *automock.TenantRepository {
  1414  				repo := &automock.TenantRepository{}
  1415  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1416  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1417  				return repo
  1418  			},
  1419  			webhookRepo: func() *automock.WebhookRepository {
  1420  				webhookRepo := &automock.WebhookRepository{}
  1421  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1422  				return webhookRepo
  1423  			},
  1424  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1425  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1426  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1427  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeWithLabels, nil).Once()
  1428  				return webhookDataInputBuilder
  1429  			},
  1430  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1431  				faRepo := &automock.FormationAssignmentRepository{}
  1432  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, testErr).Once()
  1433  				return faRepo
  1434  			},
  1435  			formationRepo: func() *automock.FormationRepository {
  1436  				repo := &automock.FormationRepository{}
  1437  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1438  				return repo
  1439  			},
  1440  			expectedErrMsg: testErr.Error(),
  1441  		},
  1442  		{
  1443  			name:                "Error when preparing details for source type application and runtime target",
  1444  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1445  			formationOperation:  model.AssignFormation,
  1446  			tenantRepo: func() *automock.TenantRepository {
  1447  				repo := &automock.TenantRepository{}
  1448  				repo.On("Get", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(gaTenantObject, nil)
  1449  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppAndTargetRuntime.TenantID).Return(TntParentID, nil)
  1450  				return repo
  1451  			},
  1452  			webhookRepo: func() *automock.WebhookRepository {
  1453  				webhookRepo := &automock.WebhookRepository{}
  1454  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1455  				return webhookRepo
  1456  			},
  1457  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1458  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1459  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1460  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeWithLabels, nil).Once()
  1461  				return webhookDataInputBuilder
  1462  			},
  1463  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1464  				faRepo := &automock.FormationAssignmentRepository{}
  1465  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetRuntimeReverse, nil).Once()
  1466  				return faRepo
  1467  			},
  1468  			formationRepo: func() *automock.FormationRepository {
  1469  				repo := &automock.FormationRepository{}
  1470  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1471  				return repo
  1472  			},
  1473  			notificationBuilder: func() *automock.NotificationBuilder {
  1474  				notificationsBuilder := &automock.NotificationBuilder{}
  1475  
  1476  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceAppAndTargetRuntime), convertFormationAssignmentFromModel(faWithSourceAppAndTargetRuntimeReverse), model.RuntimeResourceType, testCustomerTenantContext, TestTenantID).Return(nil, testErr).Once()
  1477  
  1478  				return notificationsBuilder
  1479  			},
  1480  			expectedErrMsg: testErr.Error(),
  1481  		},
  1482  		{
  1483  			name:                "Error when building notification request for source type application and runtime target",
  1484  			formationAssignment: faWithSourceAppAndTargetRuntime,
  1485  			formationOperation:  model.AssignFormation,
  1486  			tenantRepo: func() *automock.TenantRepository {
  1487  				repo := &automock.TenantRepository{}
  1488  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1489  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
  1490  				return repo
  1491  			},
  1492  			webhookRepo: func() *automock.WebhookRepository {
  1493  				webhookRepo := &automock.WebhookRepository{}
  1494  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, TestTarget, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1495  				return webhookRepo
  1496  			},
  1497  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1498  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1499  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1500  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeWithLabels, nil).Once()
  1501  				return webhookDataInputBuilder
  1502  			},
  1503  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1504  				faRepo := &automock.FormationAssignmentRepository{}
  1505  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppAndTargetRuntimeReverse, nil).Once()
  1506  				return faRepo
  1507  			},
  1508  			formationRepo: func() *automock.FormationRepository {
  1509  				repo := &automock.FormationRepository{}
  1510  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1511  				return repo
  1512  			},
  1513  			notificationBuilder: func() *automock.NotificationBuilder {
  1514  				notificationsBuilder := &automock.NotificationBuilder{}
  1515  
  1516  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, emptyRuntimeCtx, convertFormationAssignmentFromModel(faWithSourceAppAndTargetRuntime), convertFormationAssignmentFromModel(faWithSourceAppAndTargetRuntimeReverse), model.RuntimeResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1517  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testRuntimeWebhook).Return(nil, testErr).Once()
  1518  
  1519  				return notificationsBuilder
  1520  			},
  1521  			expectedErrMsg: testErr.Error(),
  1522  		},
  1523  		// runtime context formation assignment notifications with source application
  1524  		{
  1525  			name:                "Successfully generate runtime context notification when source type is application",
  1526  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1527  			formationOperation:  model.AssignFormation,
  1528  			tenantRepo: func() *automock.TenantRepository {
  1529  				repo := &automock.TenantRepository{}
  1530  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1531  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1532  				return repo
  1533  			},
  1534  			webhookRepo: func() *automock.WebhookRepository {
  1535  				webhookRepo := &automock.WebhookRepository{}
  1536  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1537  				return webhookRepo
  1538  			},
  1539  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1540  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1541  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1542  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1543  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1544  				return webhookDataInputBuilder
  1545  			},
  1546  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1547  				faRepo := &automock.FormationAssignmentRepository{}
  1548  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppCtxAndTargetRtmCtxReverse, nil).Once()
  1549  				return faRepo
  1550  			},
  1551  			formationRepo: func() *automock.FormationRepository {
  1552  				repo := &automock.FormationRepository{}
  1553  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1554  				return repo
  1555  			},
  1556  			notificationBuilder: func() *automock.NotificationBuilder {
  1557  				notificationsBuilder := &automock.NotificationBuilder{}
  1558  
  1559  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceAppCtxAndTargetRtmCtx), convertFormationAssignmentFromModel(faWithSourceAppCtxAndTargetRtmCtxReverse), model.RuntimeContextResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1560  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testRuntimeWebhook).Return(testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceAppAndTargetRtmCtx, nil).Once()
  1561  
  1562  				return notificationsBuilder
  1563  			},
  1564  			expectedNotification: testAppNotificationReqWithFormationConfigurationChangeTypeWithSourceAppAndTargetRtmCtx,
  1565  		},
  1566  		{
  1567  			name:                "Error when getting tenant fails",
  1568  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1569  			formationOperation:  model.AssignFormation,
  1570  			tenantRepo: func() *automock.TenantRepository {
  1571  				repo := &automock.TenantRepository{}
  1572  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(nil, testErr)
  1573  				return repo
  1574  			},
  1575  			expectedErrMsg: testErr.Error(),
  1576  		},
  1577  		{
  1578  			name:                "Error when getting parent customer id fails",
  1579  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1580  			formationOperation:  model.AssignFormation,
  1581  			tenantRepo: func() *automock.TenantRepository {
  1582  				repo := &automock.TenantRepository{}
  1583  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1584  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return("", testErr)
  1585  				return repo
  1586  			},
  1587  			expectedErrMsg: testErr.Error(),
  1588  		},
  1589  		{
  1590  			name:                "Error when preparing runtime context with labels for source type application",
  1591  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1592  			formationOperation:  model.AssignFormation,
  1593  			tenantRepo: func() *automock.TenantRepository {
  1594  				repo := &automock.TenantRepository{}
  1595  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1596  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1597  				return repo
  1598  			},
  1599  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1600  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1601  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(nil, testErr).Once()
  1602  				return webhookDataInputBuilder
  1603  			},
  1604  			formationRepo: func() *automock.FormationRepository {
  1605  				repo := &automock.FormationRepository{}
  1606  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1607  				return repo
  1608  			},
  1609  			expectedErrMsg: testErr.Error(),
  1610  		},
  1611  		{
  1612  			name:                "Success when runtime webhook is not found for runtime context target",
  1613  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1614  			formationOperation:  model.AssignFormation,
  1615  			tenantRepo: func() *automock.TenantRepository {
  1616  				repo := &automock.TenantRepository{}
  1617  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1618  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1619  				return repo
  1620  			},
  1621  			webhookRepo: func() *automock.WebhookRepository {
  1622  				webhookRepo := &automock.WebhookRepository{}
  1623  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testNotFoundErr).Once()
  1624  				return webhookRepo
  1625  			},
  1626  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1627  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1628  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1629  				return webhookDataInputBuilder
  1630  			},
  1631  			formationRepo: func() *automock.FormationRepository {
  1632  				repo := &automock.FormationRepository{}
  1633  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1634  				return repo
  1635  			},
  1636  		},
  1637  		{
  1638  			name:                "Error when getting runtime webhook by ID and type for runtime context target",
  1639  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1640  			formationOperation:  model.AssignFormation,
  1641  			tenantRepo: func() *automock.TenantRepository {
  1642  				repo := &automock.TenantRepository{}
  1643  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1644  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1645  				return repo
  1646  			},
  1647  			webhookRepo: func() *automock.WebhookRepository {
  1648  				webhookRepo := &automock.WebhookRepository{}
  1649  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(nil, testErr).Once()
  1650  				return webhookRepo
  1651  			},
  1652  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1653  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1654  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1655  				return webhookDataInputBuilder
  1656  			},
  1657  			formationRepo: func() *automock.FormationRepository {
  1658  				repo := &automock.FormationRepository{}
  1659  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1660  				return repo
  1661  			},
  1662  			expectedErrMsg: "while getting configuration changed webhook for runtime with ID:",
  1663  		},
  1664  		{
  1665  			name:                "Error when source type is different than application for runtime context target",
  1666  			formationAssignment: faWithSourceInvalidAndTargetRtmCtx,
  1667  			formationOperation:  model.AssignFormation,
  1668  			tenantRepo: func() *automock.TenantRepository {
  1669  				repo := &automock.TenantRepository{}
  1670  				repo.On("Get", emptyCtx, faWithSourceInvalidAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1671  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceInvalidAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1672  				return repo
  1673  			},
  1674  			webhookRepo: func() *automock.WebhookRepository {
  1675  				webhookRepo := &automock.WebhookRepository{}
  1676  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1677  				return webhookRepo
  1678  			},
  1679  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1680  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1681  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1682  				return webhookDataInputBuilder
  1683  			},
  1684  			formationRepo: func() *automock.FormationRepository {
  1685  				repo := &automock.FormationRepository{}
  1686  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1687  				return repo
  1688  			},
  1689  			expectedErrMsg: fmt.Sprintf("The formation assignmet with ID: %q and target type: %q has unsupported reverse(source) type: %q", TestID, model.FormationAssignmentTypeRuntimeContext, model.FormationAssignmentTypeRuntimeContext),
  1690  		},
  1691  		{
  1692  			name:                "Error when preparing app and app template with labels for source type application and runtime ctx target",
  1693  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1694  			formationOperation:  model.AssignFormation,
  1695  			tenantRepo: func() *automock.TenantRepository {
  1696  				repo := &automock.TenantRepository{}
  1697  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1698  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1699  				return repo
  1700  			},
  1701  			webhookRepo: func() *automock.WebhookRepository {
  1702  				webhookRepo := &automock.WebhookRepository{}
  1703  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1704  				return webhookRepo
  1705  			},
  1706  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1707  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1708  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(nil, nil, testErr).Once()
  1709  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1710  				return webhookDataInputBuilder
  1711  			},
  1712  			formationRepo: func() *automock.FormationRepository {
  1713  				repo := &automock.FormationRepository{}
  1714  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1715  				return repo
  1716  			},
  1717  			expectedErrMsg: testErr.Error(),
  1718  		},
  1719  		{
  1720  			name:                "Error when preparing runtime with labels for source type application and runtime ctx target",
  1721  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1722  			formationOperation:  model.AssignFormation,
  1723  			tenantRepo: func() *automock.TenantRepository {
  1724  				repo := &automock.TenantRepository{}
  1725  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1726  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1727  				return repo
  1728  			},
  1729  			webhookRepo: func() *automock.WebhookRepository {
  1730  				webhookRepo := &automock.WebhookRepository{}
  1731  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1732  				return webhookRepo
  1733  			},
  1734  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1735  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1736  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1737  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(nil, testErr).Once()
  1738  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1739  				return webhookDataInputBuilder
  1740  			},
  1741  			formationRepo: func() *automock.FormationRepository {
  1742  				repo := &automock.FormationRepository{}
  1743  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1744  				return repo
  1745  			},
  1746  			expectedErrMsg: testErr.Error(),
  1747  		},
  1748  		{
  1749  			name:                "Error when getting reverse FA by app source and runtime context target",
  1750  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1751  			formationOperation:  model.AssignFormation,
  1752  			tenantRepo: func() *automock.TenantRepository {
  1753  				repo := &automock.TenantRepository{}
  1754  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1755  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1756  				return repo
  1757  			},
  1758  			webhookRepo: func() *automock.WebhookRepository {
  1759  				webhookRepo := &automock.WebhookRepository{}
  1760  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1761  				return webhookRepo
  1762  			},
  1763  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1764  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1765  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1766  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1767  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1768  				return webhookDataInputBuilder
  1769  			},
  1770  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1771  				faRepo := &automock.FormationAssignmentRepository{}
  1772  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, testErr).Once()
  1773  				return faRepo
  1774  			},
  1775  			formationRepo: func() *automock.FormationRepository {
  1776  				repo := &automock.FormationRepository{}
  1777  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1778  				return repo
  1779  			},
  1780  			expectedErrMsg: testErr.Error(),
  1781  		},
  1782  		{
  1783  			name:                "Error when building details source type application and runtime context target",
  1784  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1785  			formationOperation:  model.AssignFormation,
  1786  			tenantRepo: func() *automock.TenantRepository {
  1787  				repo := &automock.TenantRepository{}
  1788  				repo.On("Get", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(gaTenantObject, nil)
  1789  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceAppCtxAndTargetRtmCtx.TenantID).Return(TntParentID, nil)
  1790  				return repo
  1791  			},
  1792  			webhookRepo: func() *automock.WebhookRepository {
  1793  				webhookRepo := &automock.WebhookRepository{}
  1794  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1795  				return webhookRepo
  1796  			},
  1797  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1798  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1799  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1800  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1801  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1802  				return webhookDataInputBuilder
  1803  			},
  1804  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1805  				faRepo := &automock.FormationAssignmentRepository{}
  1806  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppCtxAndTargetRtmCtxReverse, nil).Once()
  1807  				return faRepo
  1808  			},
  1809  			formationRepo: func() *automock.FormationRepository {
  1810  				repo := &automock.FormationRepository{}
  1811  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1812  				return repo
  1813  			},
  1814  			notificationBuilder: func() *automock.NotificationBuilder {
  1815  				notificationsBuilder := &automock.NotificationBuilder{}
  1816  
  1817  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceAppCtxAndTargetRtmCtx), convertFormationAssignmentFromModel(faWithSourceAppCtxAndTargetRtmCtxReverse), model.RuntimeContextResourceType, testCustomerTenantContext, TestTenantID).Return(nil, testErr).Once()
  1818  
  1819  				return notificationsBuilder
  1820  			},
  1821  			expectedErrMsg: testErr.Error(),
  1822  		},
  1823  		{
  1824  			name:                "Error when building notification request for source type application and runtime context target",
  1825  			formationAssignment: faWithSourceAppCtxAndTargetRtmCtx,
  1826  			formationOperation:  model.AssignFormation,
  1827  			tenantRepo: func() *automock.TenantRepository {
  1828  				repo := &automock.TenantRepository{}
  1829  				repo.On("Get", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(gaTenantObject, nil)
  1830  				repo.On("GetCustomerIDParentRecursively", emptyCtx, faWithSourceRuntimeAndTargetApp.TenantID).Return(TntParentID, nil)
  1831  				return repo
  1832  			},
  1833  			webhookRepo: func() *automock.WebhookRepository {
  1834  				webhookRepo := &automock.WebhookRepository{}
  1835  				webhookRepo.On("GetByIDAndWebhookType", emptyCtx, TestTenantID, testRuntimeID, model.RuntimeWebhookReference, model.WebhookTypeConfigurationChanged).Return(testRuntimeWebhook, nil).Once()
  1836  				return webhookRepo
  1837  			},
  1838  			webhookDataInputBuilder: func() *databuilderautomock.DataInputBuilder {
  1839  				webhookDataInputBuilder := &databuilderautomock.DataInputBuilder{}
  1840  				webhookDataInputBuilder.On("PrepareApplicationAndAppTemplateWithLabels", emptyCtx, TestTenantID, TestSource).Return(testAppWithLabels, testAppTemplateWithLabels, nil).Once()
  1841  				webhookDataInputBuilder.On("PrepareRuntimeWithLabels", emptyCtx, TestTenantID, testRuntimeID).Return(testRuntimeWithLabels, nil).Once()
  1842  				webhookDataInputBuilder.On("PrepareRuntimeContextWithLabels", emptyCtx, TestTenantID, TestTarget).Return(testRuntimeCtxWithLabels, nil).Once()
  1843  				return webhookDataInputBuilder
  1844  			},
  1845  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1846  				faRepo := &automock.FormationAssignmentRepository{}
  1847  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(faWithSourceAppCtxAndTargetRtmCtxReverse, nil).Once()
  1848  				return faRepo
  1849  			},
  1850  			formationRepo: func() *automock.FormationRepository {
  1851  				repo := &automock.FormationRepository{}
  1852  				repo.On("Get", ctx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1853  				return repo
  1854  			},
  1855  			notificationBuilder: func() *automock.NotificationBuilder {
  1856  				notificationsBuilder := &automock.NotificationBuilder{}
  1857  
  1858  				notificationsBuilder.On("PrepareDetailsForConfigurationChangeNotificationGeneration", model.AssignFormation, TestFormationID, TestFormationTemplateID, testAppTemplateWithLabels, testAppWithLabels, testRuntimeWithLabels, testRuntimeCtxWithLabels, convertFormationAssignmentFromModel(faWithSourceAppCtxAndTargetRtmCtx), convertFormationAssignmentFromModel(faWithSourceAppCtxAndTargetRtmCtxReverse), model.RuntimeContextResourceType, testCustomerTenantContext, TestTenantID).Return(details, nil).Once()
  1859  				notificationsBuilder.On("BuildFormationAssignmentNotificationRequest", ctx, TestFormationTemplateID, details, testRuntimeWebhook).Return(nil, testErr).Once()
  1860  
  1861  				return notificationsBuilder
  1862  			},
  1863  			expectedErrMsg: testErr.Error(),
  1864  		},
  1865  	}
  1866  
  1867  	for _, tCase := range testCases {
  1868  		t.Run(tCase.name, func(t *testing.T) {
  1869  			// GIVEN
  1870  			faRepo := unusedFormationAssignmentRepository()
  1871  			if tCase.formationAssignmentRepo != nil {
  1872  				faRepo = tCase.formationAssignmentRepo()
  1873  			}
  1874  
  1875  			webhookRepo := unusedWebhookRepo()
  1876  			if tCase.webhookRepo != nil {
  1877  				webhookRepo = tCase.webhookRepo()
  1878  			}
  1879  
  1880  			tenantRepo := unusedTenantRepo()
  1881  			if tCase.tenantRepo != nil {
  1882  				tenantRepo = tCase.tenantRepo()
  1883  			}
  1884  
  1885  			webhookDataInputBuilder := unusedWebhookDataInputBuilder()
  1886  			if tCase.webhookDataInputBuilder != nil {
  1887  				webhookDataInputBuilder = tCase.webhookDataInputBuilder()
  1888  			}
  1889  
  1890  			formationRepo := unusedFormationRepo()
  1891  			if tCase.formationRepo != nil {
  1892  				formationRepo = tCase.formationRepo()
  1893  			}
  1894  
  1895  			notificationBuilder := unusedNotificationBuilder()
  1896  			if tCase.notificationBuilder != nil {
  1897  				notificationBuilder = tCase.notificationBuilder()
  1898  			}
  1899  
  1900  			defer mock.AssertExpectationsForObjects(t, faRepo, webhookRepo, webhookDataInputBuilder, formationRepo, notificationBuilder)
  1901  
  1902  			faNotificationSvc := formationassignment.NewFormationAssignmentNotificationService(faRepo, nil, webhookRepo, tenantRepo, webhookDataInputBuilder, formationRepo, notificationBuilder, nil, nil, "", "")
  1903  			defer mock.AssertExpectationsForObjects(t, faRepo, webhookRepo, tenantRepo, webhookDataInputBuilder)
  1904  
  1905  			// WHEN
  1906  			notificationReq, err := faNotificationSvc.GenerateFormationAssignmentNotification(emptyCtx, tCase.formationAssignment, tCase.formationOperation)
  1907  
  1908  			// THEN
  1909  			if tCase.expectedErrMsg != "" {
  1910  				require.Error(t, err)
  1911  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
  1912  				require.Nil(t, tCase.expectedNotification)
  1913  			} else {
  1914  				require.NoError(t, err)
  1915  				require.Equal(t, tCase.expectedNotification, notificationReq)
  1916  			}
  1917  		})
  1918  	}
  1919  }
  1920  
  1921  func Test_PrepareDetailsForNotificationStatusReturned(t *testing.T) {
  1922  	emptyCtx = context.TODO()
  1923  
  1924  	faWithTargetTypeApplication := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeApplication, string(model.ReadyAssignmentState), nil)
  1925  	reverseFaWithTargetTypeApplication := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestTarget, TestSource, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeApplication, string(model.ReadyAssignmentState), nil)
  1926  
  1927  	faWithTargetTypeRuntime := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeRuntime, string(model.ReadyAssignmentState), nil)
  1928  	reverseFaWithTargetTypeRuntime := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestTarget, TestSource, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeRuntime, string(model.ReadyAssignmentState), nil)
  1929  
  1930  	faWithTargetTypeRuntimeCtx := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestSource, TestTarget, model.FormationAssignmentTypeRuntimeContext, model.FormationAssignmentTypeRuntimeContext, string(model.ReadyAssignmentState), nil)
  1931  	reverseFaWithTargetTypeRuntimeCtx := fixFormationAssignmentModelWithParameters(TestID, TestFormationID, TestTenantID, TestTarget, TestSource, model.FormationAssignmentTypeRuntimeContext, model.FormationAssignmentTypeRuntimeContext, string(model.ReadyAssignmentState), nil)
  1932  
  1933  	runtimeLabelInput := &model.LabelInput{
  1934  		Key:        rtmTypeLabelKey,
  1935  		ObjectID:   TestTarget,
  1936  		ObjectType: model.RuntimeLabelableObject,
  1937  	}
  1938  
  1939  	expectedDetailsForApp := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, faWithTargetTypeApplication, reverseFaWithTargetTypeApplication, formationconstraint.JoinPointLocation{})
  1940  
  1941  	testCases := []struct {
  1942  		name                    string
  1943  		formationAssignment     *model.FormationAssignment
  1944  		formationAssignmentRepo func() *automock.FormationAssignmentRepository
  1945  		formationRepo           func() *automock.FormationRepository
  1946  		labelSvc                func() *automock.LabelService
  1947  		runtimeCtxRepo          func() *automock.RuntimeContextRepository
  1948  		expectedDetails         *formationconstraint.NotificationStatusReturnedOperationDetails
  1949  		expectedErrMsg          string
  1950  	}{
  1951  		{
  1952  			name:                "Success for FA with target type application",
  1953  			formationAssignment: faWithTargetTypeApplication,
  1954  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1955  				faRepo := &automock.FormationAssignmentRepository{}
  1956  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(reverseFaWithTargetTypeApplication, nil).Once()
  1957  				return faRepo
  1958  			},
  1959  			formationRepo: func() *automock.FormationRepository {
  1960  				formationRepo := &automock.FormationRepository{}
  1961  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1962  				return formationRepo
  1963  			},
  1964  			labelSvc: func() *automock.LabelService {
  1965  				lblSvc := &automock.LabelService{}
  1966  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  1967  				return lblSvc
  1968  			},
  1969  			expectedDetails: expectedDetailsForApp,
  1970  		},
  1971  		{
  1972  			name:                "Success for FA with target type runtime",
  1973  			formationAssignment: faWithTargetTypeRuntime,
  1974  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1975  				faRepo := &automock.FormationAssignmentRepository{}
  1976  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(reverseFaWithTargetTypeRuntime, nil).Once()
  1977  				return faRepo
  1978  			},
  1979  			formationRepo: func() *automock.FormationRepository {
  1980  				formationRepo := &automock.FormationRepository{}
  1981  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  1982  				return formationRepo
  1983  			},
  1984  			labelSvc: func() *automock.LabelService {
  1985  				lblSvc := &automock.LabelService{}
  1986  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, runtimeLabelInput).Return(runtimeTypeLabel, nil).Once()
  1987  				return lblSvc
  1988  			},
  1989  			expectedDetails: fixNotificationStatusReturnedDetails(model.RuntimeResourceType, rtmSubtype, faWithTargetTypeRuntime, reverseFaWithTargetTypeRuntime, formationconstraint.JoinPointLocation{}),
  1990  		},
  1991  		{
  1992  			name:                "Success for FA with target type runtime context",
  1993  			formationAssignment: faWithTargetTypeRuntimeCtx,
  1994  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  1995  				faRepo := &automock.FormationAssignmentRepository{}
  1996  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(reverseFaWithTargetTypeRuntimeCtx, nil).Once()
  1997  				return faRepo
  1998  			},
  1999  			formationRepo: func() *automock.FormationRepository {
  2000  				formationRepo := &automock.FormationRepository{}
  2001  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  2002  				return formationRepo
  2003  			},
  2004  			labelSvc: func() *automock.LabelService {
  2005  				lblSvc := &automock.LabelService{}
  2006  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, runtimeLabelInput).Return(runtimeTypeLabel, nil).Once()
  2007  				return lblSvc
  2008  			},
  2009  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
  2010  				rtmCtxRepo := &automock.RuntimeContextRepository{}
  2011  				rtmCtxRepo.On("GetByID", emptyCtx, TestTenantID, TestTarget).Return(&model.RuntimeContext{RuntimeID: TestTarget}, nil).Once()
  2012  				return rtmCtxRepo
  2013  			},
  2014  			expectedDetails: fixNotificationStatusReturnedDetails(model.RuntimeContextResourceType, rtmSubtype, faWithTargetTypeRuntimeCtx, reverseFaWithTargetTypeRuntimeCtx, formationconstraint.JoinPointLocation{}),
  2015  		},
  2016  		{
  2017  			name:                "Success for application when there is no reverse fa",
  2018  			formationAssignment: faWithTargetTypeApplication,
  2019  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  2020  				faRepo := &automock.FormationAssignmentRepository{}
  2021  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, notFoundError).Once()
  2022  				return faRepo
  2023  			},
  2024  			formationRepo: func() *automock.FormationRepository {
  2025  				formationRepo := &automock.FormationRepository{}
  2026  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  2027  				return formationRepo
  2028  			},
  2029  			labelSvc: func() *automock.LabelService {
  2030  				lblSvc := &automock.LabelService{}
  2031  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  2032  				return lblSvc
  2033  			},
  2034  			expectedDetails: fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, faWithTargetTypeApplication, nil, formationconstraint.JoinPointLocation{}),
  2035  		},
  2036  		{
  2037  			name:                "Error when can't get reverse fa",
  2038  			formationAssignment: faWithTargetTypeApplication,
  2039  			formationAssignmentRepo: func() *automock.FormationAssignmentRepository {
  2040  				faRepo := &automock.FormationAssignmentRepository{}
  2041  				faRepo.On("GetReverseBySourceAndTarget", emptyCtx, TestTenantID, TestFormationID, TestSource, TestTarget).Return(nil, testErr).Once()
  2042  				return faRepo
  2043  			},
  2044  			formationRepo: func() *automock.FormationRepository {
  2045  				formationRepo := &automock.FormationRepository{}
  2046  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  2047  				return formationRepo
  2048  			},
  2049  			labelSvc: func() *automock.LabelService {
  2050  				lblSvc := &automock.LabelService{}
  2051  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  2052  				return lblSvc
  2053  			},
  2054  			expectedErrMsg: testErr.Error(),
  2055  		},
  2056  		{
  2057  			name:                "Error when can't get formation",
  2058  			formationAssignment: faWithTargetTypeApplication,
  2059  			formationRepo: func() *automock.FormationRepository {
  2060  				formationRepo := &automock.FormationRepository{}
  2061  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(nil, testErr).Once()
  2062  				return formationRepo
  2063  			},
  2064  			labelSvc: func() *automock.LabelService {
  2065  				lblSvc := &automock.LabelService{}
  2066  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  2067  				return lblSvc
  2068  			},
  2069  			expectedErrMsg: testErr.Error(),
  2070  		},
  2071  		{
  2072  			name:                "Error when can't get application label",
  2073  			formationAssignment: faWithTargetTypeApplication,
  2074  			labelSvc: func() *automock.LabelService {
  2075  				lblSvc := &automock.LabelService{}
  2076  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(nil, testErr).Once()
  2077  				return lblSvc
  2078  			},
  2079  			expectedErrMsg: testErr.Error(),
  2080  		},
  2081  		{
  2082  			name:                "Error when can't get runtime label when target type is runtime",
  2083  			formationAssignment: faWithTargetTypeRuntime,
  2084  			labelSvc: func() *automock.LabelService {
  2085  				lblSvc := &automock.LabelService{}
  2086  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, runtimeLabelInput).Return(nil, testErr).Once()
  2087  				return lblSvc
  2088  			},
  2089  			expectedErrMsg: testErr.Error(),
  2090  		},
  2091  		{
  2092  			name:                "Error when can't get runtime label when target type is runtime context",
  2093  			formationAssignment: faWithTargetTypeRuntimeCtx,
  2094  			labelSvc: func() *automock.LabelService {
  2095  				lblSvc := &automock.LabelService{}
  2096  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, runtimeLabelInput).Return(nil, testErr).Once()
  2097  				return lblSvc
  2098  			},
  2099  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
  2100  				rtmCtxRepo := &automock.RuntimeContextRepository{}
  2101  				rtmCtxRepo.On("GetByID", emptyCtx, TestTenantID, TestTarget).Return(&model.RuntimeContext{RuntimeID: TestTarget}, nil).Once()
  2102  				return rtmCtxRepo
  2103  			},
  2104  			expectedErrMsg: testErr.Error(),
  2105  		},
  2106  		{
  2107  			name:                "Error when can't get runtime context",
  2108  			formationAssignment: faWithTargetTypeRuntimeCtx,
  2109  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
  2110  				rtmCtxRepo := &automock.RuntimeContextRepository{}
  2111  				rtmCtxRepo.On("GetByID", emptyCtx, TestTenantID, TestTarget).Return(nil, testErr).Once()
  2112  				return rtmCtxRepo
  2113  			},
  2114  			expectedErrMsg: testErr.Error(),
  2115  		},
  2116  		{
  2117  			name:                "Error when the object type is unknown",
  2118  			formationAssignment: &model.FormationAssignment{TargetType: "unknown"},
  2119  			expectedErrMsg:      fmt.Sprintf("unknown object type %q", "unknown"),
  2120  		},
  2121  	}
  2122  
  2123  	for _, tCase := range testCases {
  2124  		t.Run(tCase.name, func(t *testing.T) {
  2125  			// GIVEN
  2126  			faRepo := unusedFormationAssignmentRepository()
  2127  			if tCase.formationAssignmentRepo != nil {
  2128  				faRepo = tCase.formationAssignmentRepo()
  2129  			}
  2130  			formationRepo := unusedFormationRepo()
  2131  			if tCase.formationRepo != nil {
  2132  				formationRepo = tCase.formationRepo()
  2133  			}
  2134  			labelSvc := &automock.LabelService{}
  2135  			if tCase.labelSvc != nil {
  2136  				labelSvc = tCase.labelSvc()
  2137  			}
  2138  			rtmCtxSvc := &automock.RuntimeContextRepository{}
  2139  			if tCase.runtimeCtxRepo != nil {
  2140  				rtmCtxSvc = tCase.runtimeCtxRepo()
  2141  			}
  2142  
  2143  			defer mock.AssertExpectationsForObjects(t, faRepo, formationRepo, labelSvc, rtmCtxSvc)
  2144  
  2145  			faNotificationSvc := formationassignment.NewFormationAssignmentNotificationService(faRepo, nil, nil, nil, nil, formationRepo, nil, rtmCtxSvc, labelSvc, rtmTypeLabelKey, appTypeLabelKey)
  2146  
  2147  			// WHEN
  2148  			notificationReq, err := faNotificationSvc.PrepareDetailsForNotificationStatusReturned(emptyCtx, TestTenantID, tCase.formationAssignment, model.AssignFormation)
  2149  
  2150  			// THEN
  2151  			if tCase.expectedErrMsg != "" {
  2152  				require.Error(t, err)
  2153  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
  2154  				require.Nil(t, tCase.expectedDetails)
  2155  			} else {
  2156  				require.NoError(t, err)
  2157  				require.Equal(t, tCase.expectedDetails, notificationReq)
  2158  			}
  2159  		})
  2160  	}
  2161  }
  2162  
  2163  func Test_GenerateFormationAssignmentNotificationExt(t *testing.T) {
  2164  	faRequestMapping := &formationassignment.FormationAssignmentRequestMapping{
  2165  		Request:             testAppNotificationReqWithTenantMappingType,
  2166  		FormationAssignment: faWithSourceAppAndTargetApp,
  2167  	}
  2168  	reverseFaRequestMapping := &formationassignment.FormationAssignmentRequestMapping{
  2169  		Request:             testAppNotificationReqWithTenantMappingType,
  2170  		FormationAssignment: faWithSourceAppAndTargetAppReverse,
  2171  	}
  2172  
  2173  	expectedExtNotificationReq := &webhookclient.FormationAssignmentNotificationRequestExt{
  2174  		FormationAssignmentNotificationRequest: faRequestMapping.Request,
  2175  		Operation:                              model.AssignFormation,
  2176  		FormationAssignment:                    faWithSourceAppAndTargetApp,
  2177  		ReverseFormationAssignment:             faWithSourceAppAndTargetAppReverse,
  2178  		Formation:                              formation,
  2179  		TargetSubtype:                          appSubtype,
  2180  	}
  2181  
  2182  	var testCases = []struct {
  2183  		name                       string
  2184  		faRequestMapping           *formationassignment.FormationAssignmentRequestMapping
  2185  		reverseFaRequestMapping    *formationassignment.FormationAssignmentRequestMapping
  2186  		formationRepo              func() *automock.FormationRepository
  2187  		labelSvc                   func() *automock.LabelService
  2188  		expectedExtNotificationReq *webhookclient.FormationAssignmentNotificationRequestExt
  2189  		expectedErrMsg             string
  2190  	}{
  2191  		{
  2192  			name:                    "Success",
  2193  			faRequestMapping:        faRequestMapping,
  2194  			reverseFaRequestMapping: reverseFaRequestMapping,
  2195  			formationRepo: func() *automock.FormationRepository {
  2196  				formationRepo := &automock.FormationRepository{}
  2197  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  2198  				return formationRepo
  2199  			},
  2200  			labelSvc: func() *automock.LabelService {
  2201  				lblSvc := &automock.LabelService{}
  2202  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  2203  				return lblSvc
  2204  			},
  2205  			expectedExtNotificationReq: expectedExtNotificationReq,
  2206  		},
  2207  		{
  2208  			name:             "Success when there is no reverse fa",
  2209  			faRequestMapping: faRequestMapping,
  2210  			formationRepo: func() *automock.FormationRepository {
  2211  				formationRepo := &automock.FormationRepository{}
  2212  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(formation, nil).Once()
  2213  				return formationRepo
  2214  			},
  2215  			labelSvc: func() *automock.LabelService {
  2216  				lblSvc := &automock.LabelService{}
  2217  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  2218  				return lblSvc
  2219  			},
  2220  			expectedExtNotificationReq: &webhookclient.FormationAssignmentNotificationRequestExt{
  2221  				FormationAssignmentNotificationRequest: faRequestMapping.Request,
  2222  				Operation:                              model.AssignFormation,
  2223  				FormationAssignment:                    faWithSourceAppAndTargetApp,
  2224  				ReverseFormationAssignment:             nil,
  2225  				Formation:                              formation,
  2226  				TargetSubtype:                          appSubtype,
  2227  			},
  2228  		},
  2229  		{
  2230  			name:                    "Returns error when can't get formation",
  2231  			faRequestMapping:        faRequestMapping,
  2232  			reverseFaRequestMapping: reverseFaRequestMapping,
  2233  			formationRepo: func() *automock.FormationRepository {
  2234  				formationRepo := &automock.FormationRepository{}
  2235  				formationRepo.On("Get", emptyCtx, TestFormationID, TestTenantID).Return(nil, testErr).Once()
  2236  				return formationRepo
  2237  			},
  2238  			labelSvc: func() *automock.LabelService {
  2239  				lblSvc := &automock.LabelService{}
  2240  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(applicationTypeLabel, nil).Once()
  2241  				return lblSvc
  2242  			},
  2243  			expectedErrMsg: testErr.Error(),
  2244  		},
  2245  		{
  2246  			name:                    "Returns error when can't get subtype",
  2247  			faRequestMapping:        faRequestMapping,
  2248  			reverseFaRequestMapping: reverseFaRequestMapping,
  2249  			labelSvc: func() *automock.LabelService {
  2250  				lblSvc := &automock.LabelService{}
  2251  				lblSvc.On("GetLabel", emptyCtx, TestTenantID, applicationLabelInput).Return(nil, testErr).Once()
  2252  				return lblSvc
  2253  			},
  2254  			expectedErrMsg: testErr.Error(),
  2255  		},
  2256  	}
  2257  	for _, tCase := range testCases {
  2258  		t.Run(tCase.name, func(t *testing.T) {
  2259  			// GIVEN
  2260  			formationRepo := unusedFormationRepo()
  2261  			if tCase.formationRepo != nil {
  2262  				formationRepo = tCase.formationRepo()
  2263  			}
  2264  			labelSvc := &automock.LabelService{}
  2265  			if tCase.labelSvc != nil {
  2266  				labelSvc = tCase.labelSvc()
  2267  			}
  2268  
  2269  			defer mock.AssertExpectationsForObjects(t, formationRepo, labelSvc)
  2270  
  2271  			faNotificationSvc := formationassignment.NewFormationAssignmentNotificationService(nil, nil, nil, nil, nil, formationRepo, nil, nil, labelSvc, rtmTypeLabelKey, appTypeLabelKey)
  2272  
  2273  			// WHEN
  2274  			extNotificationRequest, err := faNotificationSvc.GenerateFormationAssignmentNotificationExt(emptyCtx, tCase.faRequestMapping, tCase.reverseFaRequestMapping, model.AssignFormation)
  2275  
  2276  			// THEN
  2277  			if tCase.expectedErrMsg != "" {
  2278  				require.Error(t, err)
  2279  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
  2280  				require.Nil(t, tCase.expectedExtNotificationReq)
  2281  			} else {
  2282  				require.NoError(t, err)
  2283  				require.Equal(t, tCase.expectedExtNotificationReq, extNotificationRequest)
  2284  			}
  2285  		})
  2286  	}
  2287  }