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

     1  package datainputbuilder_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  
    11  	databuilder "github.com/kyma-incubator/compass/components/director/internal/domain/webhook/datainputbuilder"
    12  	"github.com/kyma-incubator/compass/components/director/internal/domain/webhook/datainputbuilder/automock"
    13  
    14  	"github.com/kyma-incubator/compass/components/director/internal/model"
    15  	"github.com/kyma-incubator/compass/components/director/pkg/webhook"
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/mock"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  var (
    22  	emptyCtx         = context.Background()
    23  	testErr          = errors.New("test error")
    24  	testTenantID     = "testTenantID"
    25  	testRuntimeID    = "testRuntimeID"
    26  	testRuntimeCtxID = "testRuntimeCtxID"
    27  
    28  	testLabels = map[string]*model.Label{"testLabelKey": {
    29  		ID:     "testLabelID",
    30  		Tenant: &testTenantID,
    31  		Value:  "testLabelValue",
    32  	}}
    33  
    34  	testLabelsComposite = map[string]*model.Label{"testLabelKey": {
    35  		ID:     "testLabelID",
    36  		Tenant: &testTenantID,
    37  		Value:  []string{"testLabelValue"},
    38  	}}
    39  
    40  	testRuntime = &model.Runtime{
    41  		ID:   testRuntimeID,
    42  		Name: "testRuntimeName",
    43  	}
    44  
    45  	testExpectedRuntimeWithLabels = &webhook.RuntimeWithLabels{
    46  		Runtime: testRuntime,
    47  		Labels:  convertLabels(testLabels),
    48  	}
    49  
    50  	testRuntimeCtx = &model.RuntimeContext{
    51  		ID:    testRuntimeCtxID,
    52  		Key:   "testRtmCtxKey",
    53  		Value: "testRtmCtxValue",
    54  	}
    55  
    56  	testExpectedRuntimeCtxWithLabels = &webhook.RuntimeContextWithLabels{
    57  		RuntimeContext: testRuntimeCtx,
    58  		Labels:         convertLabels(testLabels),
    59  	}
    60  )
    61  
    62  func TestWebhookDataInputBuilder_PrepareApplicationAndAppTemplateWithLabels(t *testing.T) {
    63  	testAppID := "testAppID"
    64  	testAppTemplateID := "testAppTemplateID"
    65  
    66  	testApplication := &model.Application{
    67  		Name:                  "testAppName",
    68  		ApplicationTemplateID: &testAppTemplateID,
    69  	}
    70  
    71  	testAppTemplate := &model.ApplicationTemplate{
    72  		ID:   testAppTemplateID,
    73  		Name: "testAppTemplateName",
    74  	}
    75  
    76  	testExpectedAppWithLabels := &webhook.ApplicationWithLabels{
    77  		Application: testApplication,
    78  		Labels:      convertLabels(testLabels),
    79  	}
    80  
    81  	testExpectedAppWithCompositeLabel := &webhook.ApplicationWithLabels{
    82  		Application: testApplication,
    83  		Labels:      convertLabels(testLabelsComposite),
    84  	}
    85  
    86  	testExpectedAppTemplateWithLabels := &webhook.ApplicationTemplateWithLabels{
    87  		ApplicationTemplate: testAppTemplate,
    88  		Labels:              convertLabels(testLabels),
    89  	}
    90  
    91  	testCases := []struct {
    92  		name                          string
    93  		appRepo                       func() *automock.ApplicationRepository
    94  		appTemplateRepo               func() *automock.ApplicationTemplateRepository
    95  		runtimeRepo                   func() *automock.RuntimeRepository
    96  		runtimeCtxRepo                func() *automock.RuntimeContextRepository
    97  		labelRepo                     func() *automock.LabelRepository
    98  		expectedAppWithLabels         *webhook.ApplicationWithLabels
    99  		expectedAppTemplateWithLabels *webhook.ApplicationTemplateWithLabels
   100  		expectedErrMsg                string
   101  	}{
   102  		{
   103  			name: "Success",
   104  			appRepo: func() *automock.ApplicationRepository {
   105  				appRepo := &automock.ApplicationRepository{}
   106  				appRepo.On("GetByID", emptyCtx, testTenantID, testAppID).Return(testApplication, nil).Once()
   107  				return appRepo
   108  			},
   109  			appTemplateRepo: func() *automock.ApplicationTemplateRepository {
   110  				appTmplRepo := &automock.ApplicationTemplateRepository{}
   111  				appTmplRepo.On("Get", emptyCtx, testAppTemplateID).Return(testAppTemplate, nil).Once()
   112  				return appTmplRepo
   113  			},
   114  			runtimeRepo:    unusedRuntimeRepo,
   115  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   116  			labelRepo: func() *automock.LabelRepository {
   117  				lblRepo := &automock.LabelRepository{}
   118  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.ApplicationLabelableObject, testAppID).Return(testLabels, nil).Once()
   119  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.AppTemplateLabelableObject, testAppTemplateID).Return(testLabels, nil).Once()
   120  				return lblRepo
   121  			},
   122  			expectedAppWithLabels:         testExpectedAppWithLabels,
   123  			expectedAppTemplateWithLabels: testExpectedAppTemplateWithLabels,
   124  		},
   125  		{
   126  			name: "Success when fails to unquote label",
   127  			appRepo: func() *automock.ApplicationRepository {
   128  				appRepo := &automock.ApplicationRepository{}
   129  				appRepo.On("GetByID", emptyCtx, testTenantID, testAppID).Return(testApplication, nil).Once()
   130  				return appRepo
   131  			},
   132  			appTemplateRepo: func() *automock.ApplicationTemplateRepository {
   133  				appTmplRepo := &automock.ApplicationTemplateRepository{}
   134  				appTmplRepo.On("Get", emptyCtx, testAppTemplateID).Return(testAppTemplate, nil).Once()
   135  				return appTmplRepo
   136  			},
   137  			runtimeRepo:    unusedRuntimeRepo,
   138  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   139  			labelRepo: func() *automock.LabelRepository {
   140  				lblRepo := &automock.LabelRepository{}
   141  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.ApplicationLabelableObject, testAppID).Return(testLabelsComposite, nil).Once()
   142  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.AppTemplateLabelableObject, testAppTemplateID).Return(testLabels, nil).Once()
   143  				return lblRepo
   144  			},
   145  			expectedAppWithLabels:         testExpectedAppWithCompositeLabel,
   146  			expectedAppTemplateWithLabels: testExpectedAppTemplateWithLabels,
   147  		},
   148  		{
   149  			name: "Error when getting application fail",
   150  			appRepo: func() *automock.ApplicationRepository {
   151  				appRepo := &automock.ApplicationRepository{}
   152  				appRepo.On("GetByID", emptyCtx, testTenantID, testAppID).Return(nil, testErr).Once()
   153  				return appRepo
   154  			},
   155  			appTemplateRepo: unusedAppTemplateRepo,
   156  			runtimeRepo:     unusedRuntimeRepo,
   157  			runtimeCtxRepo:  unusedRuntimeCtxRepo,
   158  			labelRepo:       unusedLabelRepo,
   159  			expectedErrMsg:  fmt.Sprintf("while getting application by ID: %q", testAppID),
   160  		},
   161  		{
   162  			name: "Error when getting application labels fail",
   163  			appRepo: func() *automock.ApplicationRepository {
   164  				appRepo := &automock.ApplicationRepository{}
   165  				appRepo.On("GetByID", emptyCtx, testTenantID, testAppID).Return(testApplication, nil).Once()
   166  				return appRepo
   167  			},
   168  			appTemplateRepo: unusedAppTemplateRepo,
   169  			runtimeRepo:     unusedRuntimeRepo,
   170  			runtimeCtxRepo:  unusedRuntimeCtxRepo,
   171  			labelRepo: func() *automock.LabelRepository {
   172  				lblRepo := &automock.LabelRepository{}
   173  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.ApplicationLabelableObject, testAppID).Return(nil, testErr).Once()
   174  				return lblRepo
   175  			},
   176  			expectedErrMsg: fmt.Sprintf("while listing labels for %q with ID: %q", model.ApplicationLabelableObject, testAppID),
   177  		},
   178  		{
   179  			name: "Error when getting application template fail",
   180  			appRepo: func() *automock.ApplicationRepository {
   181  				appRepo := &automock.ApplicationRepository{}
   182  				appRepo.On("GetByID", emptyCtx, testTenantID, testAppID).Return(testApplication, nil).Once()
   183  				return appRepo
   184  			},
   185  			appTemplateRepo: func() *automock.ApplicationTemplateRepository {
   186  				appTmplRepo := &automock.ApplicationTemplateRepository{}
   187  				appTmplRepo.On("Get", emptyCtx, testAppTemplateID).Return(nil, testErr).Once()
   188  				return appTmplRepo
   189  			},
   190  			runtimeRepo:    unusedRuntimeRepo,
   191  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   192  			labelRepo: func() *automock.LabelRepository {
   193  				lblRepo := &automock.LabelRepository{}
   194  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.ApplicationLabelableObject, testAppID).Return(testLabels, nil).Once()
   195  				return lblRepo
   196  			},
   197  			expectedErrMsg: fmt.Sprintf("while getting application template with ID: %q", testAppTemplateID),
   198  		},
   199  		{
   200  			name: "Error when getting application template labels fail",
   201  			appRepo: func() *automock.ApplicationRepository {
   202  				appRepo := &automock.ApplicationRepository{}
   203  				appRepo.On("GetByID", emptyCtx, testTenantID, testAppID).Return(testApplication, nil).Once()
   204  				return appRepo
   205  			},
   206  			appTemplateRepo: func() *automock.ApplicationTemplateRepository {
   207  				appTmplRepo := &automock.ApplicationTemplateRepository{}
   208  				appTmplRepo.On("Get", emptyCtx, testAppTemplateID).Return(testAppTemplate, nil).Once()
   209  				return appTmplRepo
   210  			},
   211  			runtimeRepo:    unusedRuntimeRepo,
   212  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   213  			labelRepo: func() *automock.LabelRepository {
   214  				lblRepo := &automock.LabelRepository{}
   215  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.ApplicationLabelableObject, testAppID).Return(testLabels, nil).Once()
   216  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.AppTemplateLabelableObject, testAppTemplateID).Return(nil, testErr).Once()
   217  				return lblRepo
   218  			},
   219  			expectedErrMsg: fmt.Sprintf("while listing labels for %q with ID: %q", model.AppTemplateLabelableObject, testAppTemplateID),
   220  		},
   221  	}
   222  
   223  	for _, tCase := range testCases {
   224  		t.Run(tCase.name, func(t *testing.T) {
   225  			// GIVEN
   226  			appRepo := tCase.appRepo()
   227  			appTemplateRepo := tCase.appTemplateRepo()
   228  			runtimeRepo := tCase.runtimeRepo()
   229  			runtimeCtxRepo := tCase.runtimeCtxRepo()
   230  			labelRepo := tCase.labelRepo()
   231  			defer mock.AssertExpectationsForObjects(t, appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   232  
   233  			webhookDataInputBuilder := databuilder.NewWebhookDataInputBuilder(appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   234  
   235  			// WHEN
   236  			appWithLabels, appTemplateWithLabels, err := webhookDataInputBuilder.PrepareApplicationAndAppTemplateWithLabels(emptyCtx, testTenantID, testAppID)
   237  
   238  			// THEN
   239  			if tCase.expectedErrMsg != "" {
   240  				require.Error(t, err)
   241  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
   242  				require.Nil(t, appWithLabels)
   243  				require.Nil(t, appTemplateWithLabels)
   244  			} else {
   245  				require.NoError(t, err)
   246  				require.Equal(t, tCase.expectedAppWithLabels, appWithLabels)
   247  				require.Equal(t, tCase.expectedAppTemplateWithLabels, appTemplateWithLabels)
   248  			}
   249  		})
   250  	}
   251  }
   252  
   253  func TestWebhookDataInputBuilder_PrepareRuntimeWithLabels(t *testing.T) {
   254  	testCases := []struct {
   255  		name                          string
   256  		appRepo                       func() *automock.ApplicationRepository
   257  		appTemplateRepo               func() *automock.ApplicationTemplateRepository
   258  		runtimeRepo                   func() *automock.RuntimeRepository
   259  		runtimeCtxRepo                func() *automock.RuntimeContextRepository
   260  		labelRepo                     func() *automock.LabelRepository
   261  		expectedAppWithLabels         *webhook.ApplicationWithLabels
   262  		expectedAppTemplateWithLabels *webhook.ApplicationTemplateWithLabels
   263  		expectedRuntimeWithLabels     *webhook.RuntimeWithLabels
   264  		expectedRuntimeCtxWithLabels  *webhook.RuntimeContextWithLabels
   265  		expectedErrMsg                string
   266  	}{
   267  		{
   268  			name:            "Success",
   269  			appRepo:         unusedAppRepo,
   270  			appTemplateRepo: unusedAppTemplateRepo,
   271  			runtimeRepo: func() *automock.RuntimeRepository {
   272  				rtmRepo := &automock.RuntimeRepository{}
   273  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntime, nil).Once()
   274  				return rtmRepo
   275  			},
   276  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   277  			labelRepo: func() *automock.LabelRepository {
   278  				lblRepo := &automock.LabelRepository{}
   279  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeLabelableObject, testRuntimeID).Return(testLabels, nil).Once()
   280  				return lblRepo
   281  			},
   282  			expectedRuntimeWithLabels: testExpectedRuntimeWithLabels,
   283  		},
   284  		{
   285  			name:            "Error when getting runtime fail",
   286  			appRepo:         unusedAppRepo,
   287  			appTemplateRepo: unusedAppTemplateRepo,
   288  			runtimeRepo: func() *automock.RuntimeRepository {
   289  				rtmRepo := &automock.RuntimeRepository{}
   290  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(nil, testErr).Once()
   291  				return rtmRepo
   292  			},
   293  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   294  			labelRepo:      unusedLabelRepo,
   295  			expectedErrMsg: fmt.Sprintf("while getting runtime by ID: %q", testRuntimeID),
   296  		},
   297  		{
   298  			name:            "Error when getting runtime labels fail",
   299  			appRepo:         unusedAppRepo,
   300  			appTemplateRepo: unusedAppTemplateRepo,
   301  			runtimeRepo: func() *automock.RuntimeRepository {
   302  				rtmRepo := &automock.RuntimeRepository{}
   303  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntime, nil).Once()
   304  				return rtmRepo
   305  			},
   306  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   307  			labelRepo: func() *automock.LabelRepository {
   308  				lblRepo := &automock.LabelRepository{}
   309  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeLabelableObject, testRuntimeID).Return(nil, testErr).Once()
   310  				return lblRepo
   311  			},
   312  			expectedErrMsg: fmt.Sprintf("while listing labels for %q with ID: %q", model.RuntimeLabelableObject, testRuntimeID),
   313  		},
   314  	}
   315  
   316  	for _, tCase := range testCases {
   317  		t.Run(tCase.name, func(t *testing.T) {
   318  			// GIVEN
   319  			appRepo := tCase.appRepo()
   320  			appTemplateRepo := tCase.appTemplateRepo()
   321  			runtimeRepo := tCase.runtimeRepo()
   322  			runtimeCtxRepo := tCase.runtimeCtxRepo()
   323  			labelRepo := tCase.labelRepo()
   324  			defer mock.AssertExpectationsForObjects(t, appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   325  
   326  			webhookDataInputBuilder := databuilder.NewWebhookDataInputBuilder(appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   327  
   328  			// WHEN
   329  			runtimeWithLabels, err := webhookDataInputBuilder.PrepareRuntimeWithLabels(emptyCtx, testTenantID, testRuntimeID)
   330  
   331  			// THEN
   332  			if tCase.expectedErrMsg != "" {
   333  				require.Error(t, err)
   334  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
   335  				require.Nil(t, runtimeWithLabels)
   336  			} else {
   337  				require.NoError(t, err)
   338  				require.Equal(t, tCase.expectedRuntimeWithLabels, runtimeWithLabels)
   339  			}
   340  		})
   341  	}
   342  }
   343  
   344  func TestWebhookDataInputBuilder_PrepareRuntimeContextWithLabels(t *testing.T) {
   345  	testCases := []struct {
   346  		name                          string
   347  		appRepo                       func() *automock.ApplicationRepository
   348  		appTemplateRepo               func() *automock.ApplicationTemplateRepository
   349  		runtimeRepo                   func() *automock.RuntimeRepository
   350  		runtimeCtxRepo                func() *automock.RuntimeContextRepository
   351  		labelRepo                     func() *automock.LabelRepository
   352  		expectedAppWithLabels         *webhook.ApplicationWithLabels
   353  		expectedAppTemplateWithLabels *webhook.ApplicationTemplateWithLabels
   354  		expectedRuntimeWithLabels     *webhook.RuntimeWithLabels
   355  		expectedRuntimeCtxWithLabels  *webhook.RuntimeContextWithLabels
   356  		expectedErrMsg                string
   357  	}{
   358  		{
   359  			name:            "Success",
   360  			appRepo:         unusedAppRepo,
   361  			appTemplateRepo: unusedAppTemplateRepo,
   362  			runtimeRepo:     unusedRuntimeRepo,
   363  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
   364  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   365  				rtmCtxRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeCtxID).Return(testRuntimeCtx, nil).Once()
   366  				return rtmCtxRepo
   367  			},
   368  			labelRepo: func() *automock.LabelRepository {
   369  				lblRepo := &automock.LabelRepository{}
   370  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeContextLabelableObject, testRuntimeCtxID).Return(testLabels, nil).Once()
   371  				return lblRepo
   372  			},
   373  			expectedRuntimeCtxWithLabels: testExpectedRuntimeCtxWithLabels,
   374  		},
   375  		{
   376  			name:            "Error when getting runtime context fail",
   377  			appRepo:         unusedAppRepo,
   378  			appTemplateRepo: unusedAppTemplateRepo,
   379  			runtimeRepo:     unusedRuntimeRepo,
   380  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
   381  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   382  				rtmCtxRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeCtxID).Return(nil, testErr).Once()
   383  				return rtmCtxRepo
   384  			},
   385  			labelRepo:      unusedLabelRepo,
   386  			expectedErrMsg: fmt.Sprintf("while getting runtime context by ID: %q", testRuntimeCtxID),
   387  		},
   388  		{
   389  			name:            "Error when getting runtime context labels fail",
   390  			appRepo:         unusedAppRepo,
   391  			appTemplateRepo: unusedAppTemplateRepo,
   392  			runtimeRepo:     unusedRuntimeRepo,
   393  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
   394  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   395  				rtmCtxRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeCtxID).Return(testRuntimeCtx, nil).Once()
   396  				return rtmCtxRepo
   397  			},
   398  			labelRepo: func() *automock.LabelRepository {
   399  				lblRepo := &automock.LabelRepository{}
   400  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeContextLabelableObject, testRuntimeCtxID).Return(nil, testErr).Once()
   401  				return lblRepo
   402  			},
   403  			expectedErrMsg: fmt.Sprintf("while listing labels for %q with ID: %q", model.RuntimeContextLabelableObject, testRuntimeCtxID),
   404  		},
   405  	}
   406  
   407  	for _, tCase := range testCases {
   408  		t.Run(tCase.name, func(t *testing.T) {
   409  			// GIVEN
   410  			appRepo := tCase.appRepo()
   411  			appTemplateRepo := tCase.appTemplateRepo()
   412  			runtimeRepo := tCase.runtimeRepo()
   413  			runtimeCtxRepo := tCase.runtimeCtxRepo()
   414  			labelRepo := tCase.labelRepo()
   415  			defer mock.AssertExpectationsForObjects(t, appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   416  
   417  			webhookDataInputBuilder := databuilder.NewWebhookDataInputBuilder(appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   418  
   419  			// WHEN
   420  			runtimeCtxWithLabels, err := webhookDataInputBuilder.PrepareRuntimeContextWithLabels(emptyCtx, testTenantID, testRuntimeCtxID)
   421  
   422  			// THEN
   423  			if tCase.expectedErrMsg != "" {
   424  				require.Error(t, err)
   425  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
   426  				require.Nil(t, runtimeCtxWithLabels)
   427  			} else {
   428  				require.NoError(t, err)
   429  				require.Equal(t, tCase.expectedRuntimeCtxWithLabels, runtimeCtxWithLabels)
   430  			}
   431  		})
   432  	}
   433  }
   434  
   435  func TestWebhookDataInputBuilder_PrepareRuntimeAndRuntimeContextWithLabels(t *testing.T) {
   436  	testCases := []struct {
   437  		name                          string
   438  		appRepo                       func() *automock.ApplicationRepository
   439  		appTemplateRepo               func() *automock.ApplicationTemplateRepository
   440  		runtimeRepo                   func() *automock.RuntimeRepository
   441  		runtimeCtxRepo                func() *automock.RuntimeContextRepository
   442  		labelRepo                     func() *automock.LabelRepository
   443  		expectedAppWithLabels         *webhook.ApplicationWithLabels
   444  		expectedAppTemplateWithLabels *webhook.ApplicationTemplateWithLabels
   445  		expectedRuntimeWithLabels     *webhook.RuntimeWithLabels
   446  		expectedRuntimeCtxWithLabels  *webhook.RuntimeContextWithLabels
   447  		expectedErrMsg                string
   448  	}{
   449  		{
   450  			name:            "Success",
   451  			appRepo:         unusedAppRepo,
   452  			appTemplateRepo: unusedAppTemplateRepo,
   453  			runtimeRepo: func() *automock.RuntimeRepository {
   454  				rtmRepo := &automock.RuntimeRepository{}
   455  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntime, nil).Once()
   456  				return rtmRepo
   457  			},
   458  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
   459  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   460  				rtmCtxRepo.On("GetByRuntimeID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntimeCtx, nil).Once()
   461  				return rtmCtxRepo
   462  			},
   463  			labelRepo: func() *automock.LabelRepository {
   464  				lblRepo := &automock.LabelRepository{}
   465  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeLabelableObject, testRuntimeID).Return(testLabels, nil).Once()
   466  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeContextLabelableObject, testRuntimeCtxID).Return(testLabels, nil).Once()
   467  				return lblRepo
   468  			},
   469  			expectedRuntimeWithLabels:    testExpectedRuntimeWithLabels,
   470  			expectedRuntimeCtxWithLabels: testExpectedRuntimeCtxWithLabels,
   471  		},
   472  		{
   473  			name:            "Error when preparing runtime with labels fail",
   474  			appRepo:         unusedAppRepo,
   475  			appTemplateRepo: unusedAppTemplateRepo,
   476  			runtimeRepo: func() *automock.RuntimeRepository {
   477  				rtmRepo := &automock.RuntimeRepository{}
   478  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(nil, testErr).Once()
   479  				return rtmRepo
   480  			},
   481  			runtimeCtxRepo: unusedRuntimeCtxRepo,
   482  			labelRepo:      unusedLabelRepo,
   483  			expectedErrMsg: fmt.Sprintf("while getting runtime by ID: %q", testRuntimeID),
   484  		},
   485  		{
   486  			name:            "Error when getting runtime context by runtime ID fail",
   487  			appRepo:         unusedAppRepo,
   488  			appTemplateRepo: unusedAppTemplateRepo,
   489  			runtimeRepo: func() *automock.RuntimeRepository {
   490  				rtmRepo := &automock.RuntimeRepository{}
   491  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntime, nil).Once()
   492  				return rtmRepo
   493  			},
   494  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
   495  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   496  				rtmCtxRepo.On("GetByRuntimeID", emptyCtx, testTenantID, testRuntimeID).Return(nil, testErr).Once()
   497  				return rtmCtxRepo
   498  			},
   499  			labelRepo: func() *automock.LabelRepository {
   500  				lblRepo := &automock.LabelRepository{}
   501  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeLabelableObject, testRuntimeID).Return(testLabels, nil).Once()
   502  				return lblRepo
   503  			},
   504  			expectedErrMsg: fmt.Sprintf("while getting runtime context for runtime with ID: %q", testRuntimeID),
   505  		},
   506  		{
   507  			name:            "Error when getting runtime context labels fail",
   508  			appRepo:         unusedAppRepo,
   509  			appTemplateRepo: unusedAppTemplateRepo,
   510  			runtimeRepo: func() *automock.RuntimeRepository {
   511  				rtmRepo := &automock.RuntimeRepository{}
   512  				rtmRepo.On("GetByID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntime, nil).Once()
   513  				return rtmRepo
   514  			},
   515  			runtimeCtxRepo: func() *automock.RuntimeContextRepository {
   516  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   517  				rtmCtxRepo.On("GetByRuntimeID", emptyCtx, testTenantID, testRuntimeID).Return(testRuntimeCtx, nil).Once()
   518  				return rtmCtxRepo
   519  			},
   520  			labelRepo: func() *automock.LabelRepository {
   521  				lblRepo := &automock.LabelRepository{}
   522  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeLabelableObject, testRuntimeID).Return(testLabels, nil).Once()
   523  				lblRepo.On("ListForObject", emptyCtx, testTenantID, model.RuntimeContextLabelableObject, testRuntimeCtxID).Return(nil, testErr).Once()
   524  				return lblRepo
   525  			},
   526  			expectedErrMsg: fmt.Sprintf("while listing labels for %q with ID: %q", model.RuntimeContextLabelableObject, testRuntimeCtxID),
   527  		},
   528  	}
   529  
   530  	for _, tCase := range testCases {
   531  		t.Run(tCase.name, func(t *testing.T) {
   532  			// GIVEN
   533  			appRepo := tCase.appRepo()
   534  			appTemplateRepo := tCase.appTemplateRepo()
   535  			runtimeRepo := tCase.runtimeRepo()
   536  			runtimeCtxRepo := tCase.runtimeCtxRepo()
   537  			labelRepo := tCase.labelRepo()
   538  			defer mock.AssertExpectationsForObjects(t, appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   539  
   540  			webhookDataInputBuilder := databuilder.NewWebhookDataInputBuilder(appRepo, appTemplateRepo, runtimeRepo, runtimeCtxRepo, labelRepo)
   541  
   542  			// WHEN
   543  			runtimeWithLabels, runtimeCtxWithLabels, err := webhookDataInputBuilder.PrepareRuntimeAndRuntimeContextWithLabels(emptyCtx, testTenantID, testRuntimeID)
   544  
   545  			// THEN
   546  			if tCase.expectedErrMsg != "" {
   547  				require.Error(t, err)
   548  				require.Contains(t, err.Error(), tCase.expectedErrMsg)
   549  				require.Nil(t, runtimeWithLabels)
   550  				require.Nil(t, runtimeCtxWithLabels)
   551  			} else {
   552  				require.NoError(t, err)
   553  				require.Equal(t, tCase.expectedRuntimeWithLabels, runtimeWithLabels)
   554  				require.Equal(t, tCase.expectedRuntimeCtxWithLabels, runtimeCtxWithLabels)
   555  			}
   556  		})
   557  	}
   558  }
   559  
   560  func TestWebhookDataInputBuilder_PrepareRuntimesAndRuntimeContextsMappingsInFormation(t *testing.T) {
   561  	ctx := context.TODO()
   562  
   563  	testCases := []struct {
   564  		Name                            string
   565  		RuntimeRepoFN                   func() *automock.RuntimeRepository
   566  		RuntimeContextRepoFN            func() *automock.RuntimeContextRepository
   567  		LabelRepoFN                     func() *automock.LabelRepository
   568  		FormationName                   string
   569  		ExpectedRuntimesMappings        map[string]*webhook.RuntimeWithLabels
   570  		ExpectedRuntimeContextsMappings map[string]*webhook.RuntimeContextWithLabels
   571  		ExpectedErrMessage              string
   572  	}{
   573  		{
   574  			Name: "success",
   575  			RuntimeRepoFN: func() *automock.RuntimeRepository {
   576  				repo := &automock.RuntimeRepository{}
   577  				repo.On("ListByIDs", ctx, Tnt, mock.MatchedBy(func(ids []string) bool {
   578  					return checkIfEqual(ids, []string{RuntimeContextRuntimeID, RuntimeID})
   579  				})).Return([]*model.Runtime{fixRuntimeModel(RuntimeContextRuntimeID), fixRuntimeModel(RuntimeID)}, nil).Once()
   580  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.Runtime{fixRuntimeModel(RuntimeID)}, nil).Once()
   581  				return repo
   582  			},
   583  			RuntimeContextRepoFN: func() *automock.RuntimeContextRepository {
   584  				repo := &automock.RuntimeContextRepository{}
   585  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.RuntimeContext{fixRuntimeContextModel(), fixRuntimeContextModelWithRuntimeID(RuntimeID)}, nil).Once()
   586  				return repo
   587  			},
   588  			LabelRepoFN: func() *automock.LabelRepository {
   589  				repo := &automock.LabelRepository{}
   590  				repo.On("ListForObjectIDs", ctx, Tnt, model.RuntimeLabelableObject, mock.MatchedBy(func(ids []string) bool {
   591  					return checkIfEqual(ids, []string{RuntimeID, RuntimeContextRuntimeID, RuntimeID})
   592  				})).Return(map[string]map[string]interface{}{
   593  					RuntimeID:               fixRuntimeLabelsMap(),
   594  					RuntimeContextRuntimeID: fixRuntimeLabelsMap(),
   595  				}, nil).Once()
   596  				repo.On("ListForObjectIDs", ctx, Tnt, model.RuntimeContextLabelableObject, []string{RuntimeContextID, RuntimeContext2ID}).Return(map[string]map[string]interface{}{
   597  					RuntimeContextID:  fixRuntimeContextLabelsMap(),
   598  					RuntimeContext2ID: fixRuntimeContextLabelsMap(),
   599  				}, nil).Once()
   600  				return repo
   601  			},
   602  			FormationName:                   ScenarioName,
   603  			ExpectedRuntimesMappings:        runtimeMappings,
   604  			ExpectedRuntimeContextsMappings: runtimeContextMappings,
   605  			ExpectedErrMessage:              "",
   606  		},
   607  		{
   608  			Name: "error when listing runtime contexts labels",
   609  			RuntimeRepoFN: func() *automock.RuntimeRepository {
   610  				repo := &automock.RuntimeRepository{}
   611  				repo.On("ListByIDs", ctx, Tnt, mock.MatchedBy(func(ids []string) bool {
   612  					return checkIfEqual(ids, []string{RuntimeContextRuntimeID, RuntimeID})
   613  				})).Return([]*model.Runtime{fixRuntimeModel(RuntimeContextRuntimeID), fixRuntimeModel(RuntimeID)}, nil).Once()
   614  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.Runtime{fixRuntimeModel(RuntimeID)}, nil).Once()
   615  				return repo
   616  			},
   617  			RuntimeContextRepoFN: func() *automock.RuntimeContextRepository {
   618  				repo := &automock.RuntimeContextRepository{}
   619  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.RuntimeContext{fixRuntimeContextModel(), fixRuntimeContextModelWithRuntimeID(RuntimeID)}, nil).Once()
   620  				return repo
   621  			},
   622  			LabelRepoFN: func() *automock.LabelRepository {
   623  				repo := &automock.LabelRepository{}
   624  				repo.On("ListForObjectIDs", ctx, Tnt, model.RuntimeLabelableObject, mock.MatchedBy(func(ids []string) bool {
   625  					return checkIfEqual(ids, []string{RuntimeID, RuntimeContextRuntimeID, RuntimeID})
   626  				})).Return(map[string]map[string]interface{}{
   627  					RuntimeID:               fixRuntimeLabelsMap(),
   628  					RuntimeContextRuntimeID: fixRuntimeLabelsMap(),
   629  				}, nil).Once()
   630  				repo.On("ListForObjectIDs", ctx, Tnt, model.RuntimeContextLabelableObject, []string{RuntimeContextID, RuntimeContext2ID}).Return(nil, testErr).Once()
   631  				return repo
   632  			},
   633  			FormationName:      ScenarioName,
   634  			ExpectedErrMessage: "while listing labels for runtime contexts",
   635  		},
   636  		{
   637  			Name: "error when listing runtimes labels",
   638  			RuntimeRepoFN: func() *automock.RuntimeRepository {
   639  				repo := &automock.RuntimeRepository{}
   640  				repo.On("ListByIDs", ctx, Tnt, mock.MatchedBy(func(ids []string) bool {
   641  					return checkIfEqual(ids, []string{RuntimeContextRuntimeID, RuntimeID})
   642  				})).Return([]*model.Runtime{fixRuntimeModel(RuntimeContextRuntimeID), fixRuntimeModel(RuntimeID)}, nil).Once()
   643  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.Runtime{fixRuntimeModel(RuntimeID)}, nil).Once()
   644  				return repo
   645  			},
   646  			RuntimeContextRepoFN: func() *automock.RuntimeContextRepository {
   647  				repo := &automock.RuntimeContextRepository{}
   648  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.RuntimeContext{fixRuntimeContextModel(), fixRuntimeContextModelWithRuntimeID(RuntimeID)}, nil).Once()
   649  				return repo
   650  			},
   651  			LabelRepoFN: func() *automock.LabelRepository {
   652  				repo := &automock.LabelRepository{}
   653  				repo.On("ListForObjectIDs", ctx, Tnt, model.RuntimeLabelableObject, mock.MatchedBy(func(ids []string) bool {
   654  					return checkIfEqual(ids, []string{RuntimeID, RuntimeContextRuntimeID, RuntimeID})
   655  				})).Return(nil, testErr).Once()
   656  				return repo
   657  			},
   658  			FormationName:      ScenarioName,
   659  			ExpectedErrMessage: "while listing runtime labels",
   660  		},
   661  		{
   662  			Name: "error when listing parent runtimes",
   663  			RuntimeRepoFN: func() *automock.RuntimeRepository {
   664  				repo := &automock.RuntimeRepository{}
   665  				repo.On("ListByIDs", ctx, Tnt, mock.MatchedBy(func(ids []string) bool {
   666  					return checkIfEqual(ids, []string{RuntimeContextRuntimeID, RuntimeID})
   667  				})).Return(nil, testErr).Once()
   668  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.Runtime{fixRuntimeModel(RuntimeID)}, nil).Once()
   669  				return repo
   670  			},
   671  			RuntimeContextRepoFN: func() *automock.RuntimeContextRepository {
   672  				repo := &automock.RuntimeContextRepository{}
   673  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.RuntimeContext{fixRuntimeContextModel(), fixRuntimeContextModelWithRuntimeID(RuntimeID)}, nil).Once()
   674  				return repo
   675  			},
   676  			FormationName:      ScenarioName,
   677  			ExpectedErrMessage: "while listing parent runtimes of runtime contexts in scenario",
   678  		},
   679  		{
   680  			Name: "error when listing runtime contexts",
   681  			RuntimeRepoFN: func() *automock.RuntimeRepository {
   682  				repo := &automock.RuntimeRepository{}
   683  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return([]*model.Runtime{fixRuntimeModel(RuntimeID)}, nil).Once()
   684  				return repo
   685  			},
   686  			RuntimeContextRepoFN: func() *automock.RuntimeContextRepository {
   687  				repo := &automock.RuntimeContextRepository{}
   688  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return(nil, testErr)
   689  				return repo
   690  			},
   691  			FormationName:      ScenarioName,
   692  			ExpectedErrMessage: "while listing runtime contexts in scenario",
   693  		},
   694  		{
   695  			Name: "error when listing runtimes",
   696  			RuntimeRepoFN: func() *automock.RuntimeRepository {
   697  				repo := &automock.RuntimeRepository{}
   698  				repo.On("ListByScenarios", ctx, Tnt, []string{ScenarioName}).Return(nil, testErr).Once()
   699  				return repo
   700  			},
   701  			FormationName:      ScenarioName,
   702  			ExpectedErrMessage: "while listing runtimes in scenario",
   703  		},
   704  	}
   705  
   706  	for _, testCase := range testCases {
   707  		t.Run(testCase.Name, func(t *testing.T) {
   708  			// GIVEN
   709  			runtimeRepo := unusedRuntimeRepo()
   710  			if testCase.RuntimeRepoFN != nil {
   711  				runtimeRepo = testCase.RuntimeRepoFN()
   712  			}
   713  			runtimeContextRepo := unusedRuntimeCtxRepo()
   714  			if testCase.RuntimeContextRepoFN != nil {
   715  				runtimeContextRepo = testCase.RuntimeContextRepoFN()
   716  			}
   717  			labelRepo := unusedLabelRepo()
   718  			if testCase.LabelRepoFN != nil {
   719  				labelRepo = testCase.LabelRepoFN()
   720  			}
   721  
   722  			webhookDataInputBuilder := databuilder.NewWebhookDataInputBuilder(nil, nil, runtimeRepo, runtimeContextRepo, labelRepo)
   723  
   724  			// WHEN
   725  			runtimeMappings, runtimeContextMappings, err := webhookDataInputBuilder.PrepareRuntimesAndRuntimeContextsMappingsInFormation(emptyCtx, Tnt, testCase.FormationName)
   726  
   727  			// THEN
   728  			if testCase.ExpectedErrMessage == "" {
   729  				require.NoError(t, err)
   730  				assert.Equal(t, testCase.ExpectedRuntimesMappings, runtimeMappings)
   731  				assert.Equal(t, testCase.ExpectedRuntimeContextsMappings, runtimeContextMappings)
   732  			} else {
   733  				require.Error(t, err)
   734  				require.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   735  				require.Nil(t, runtimeMappings, runtimeContextMappings)
   736  			}
   737  
   738  			mock.AssertExpectationsForObjects(t, runtimeRepo, runtimeContextRepo, labelRepo)
   739  		})
   740  	}
   741  }
   742  
   743  func TestWebhookDataInputBuilder_PrepareApplicationMappingsInFormation(t *testing.T) {
   744  	ctx := context.TODO()
   745  
   746  	testCases := []struct {
   747  		Name                         string
   748  		ApplicationRepoFN            func() *automock.ApplicationRepository
   749  		ApplicationTemplateRepoFN    func() *automock.ApplicationTemplateRepository
   750  		LabelRepoFN                  func() *automock.LabelRepository
   751  		FormationName                string
   752  		ExpectedApplicationsMappings map[string]*webhook.ApplicationWithLabels
   753  		ExpectedAppTemplateMappings  map[string]*webhook.ApplicationTemplateWithLabels
   754  		ExpectedErrMessage           string
   755  	}{
   756  		{
   757  			Name: "success",
   758  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   759  				repo := &automock.ApplicationRepository{}
   760  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return([]*model.Application{fixApplicationModel(ApplicationID), fixApplicationModelWithoutTemplate(Application2ID)}, nil).Once()
   761  				return repo
   762  			},
   763  			ApplicationTemplateRepoFN: func() *automock.ApplicationTemplateRepository {
   764  				repo := &automock.ApplicationTemplateRepository{}
   765  				repo.On("ListByIDs", ctx, []string{ApplicationTemplateID}).Return([]*model.ApplicationTemplate{fixApplicationTemplateModel()}, nil).Once()
   766  				return repo
   767  			},
   768  			LabelRepoFN: func() *automock.LabelRepository {
   769  				repo := &automock.LabelRepository{}
   770  				repo.On("ListForObjectIDs", ctx, Tnt, model.ApplicationLabelableObject, mock.MatchedBy(func(ids []string) bool { return checkIfEqual(ids, []string{ApplicationID, Application2ID}) })).Return(map[string]map[string]interface{}{
   771  					ApplicationID:  fixApplicationLabelsMap(),
   772  					Application2ID: fixApplicationLabelsMap(),
   773  				}, nil).Once()
   774  				repo.On("ListForObjectIDs", ctx, Tnt, model.AppTemplateLabelableObject, []string{ApplicationTemplateID}).Return(map[string]map[string]interface{}{
   775  					ApplicationTemplateID: fixApplicationTemplateLabelsMap(),
   776  				}, nil).Once()
   777  				return repo
   778  			},
   779  			FormationName:                ScenarioName,
   780  			ExpectedApplicationsMappings: applicationMappings,
   781  			ExpectedAppTemplateMappings:  applicationTemplateMappings,
   782  			ExpectedErrMessage:           "",
   783  		},
   784  		{
   785  			Name: "success when fails to unquote label",
   786  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   787  				repo := &automock.ApplicationRepository{}
   788  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return([]*model.Application{fixApplicationModel(ApplicationID), fixApplicationModelWithoutTemplate(Application2ID)}, nil).Once()
   789  				return repo
   790  			},
   791  			ApplicationTemplateRepoFN: func() *automock.ApplicationTemplateRepository {
   792  				repo := &automock.ApplicationTemplateRepository{}
   793  				repo.On("ListByIDs", ctx, []string{ApplicationTemplateID}).Return([]*model.ApplicationTemplate{fixApplicationTemplateModel()}, nil).Once()
   794  				return repo
   795  			},
   796  			LabelRepoFN: func() *automock.LabelRepository {
   797  				repo := &automock.LabelRepository{}
   798  				repo.On("ListForObjectIDs", ctx, Tnt, model.ApplicationLabelableObject, mock.MatchedBy(func(ids []string) bool { return checkIfEqual(ids, []string{ApplicationID, Application2ID}) })).Return(map[string]map[string]interface{}{
   799  					ApplicationID:  fixApplicationLabelsMapWithUnquotableLabels(),
   800  					Application2ID: fixApplicationLabelsMap(),
   801  				}, nil).Once()
   802  				repo.On("ListForObjectIDs", ctx, Tnt, model.AppTemplateLabelableObject, []string{ApplicationTemplateID}).Return(map[string]map[string]interface{}{
   803  					ApplicationTemplateID: fixApplicationTemplateLabelsMap(),
   804  				}, nil).Once()
   805  				return repo
   806  			},
   807  			FormationName:                ScenarioName,
   808  			ExpectedApplicationsMappings: applicationMappingsWithCompositeLabel,
   809  			ExpectedAppTemplateMappings:  applicationTemplateMappings,
   810  			ExpectedErrMessage:           "",
   811  		},
   812  		{
   813  			Name: "success when there are no applications in scenario",
   814  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   815  				repo := &automock.ApplicationRepository{}
   816  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return([]*model.Application{}, nil).Once()
   817  				return repo
   818  			},
   819  			FormationName:                ScenarioName,
   820  			ExpectedApplicationsMappings: make(map[string]*webhook.ApplicationWithLabels, 0),
   821  			ExpectedAppTemplateMappings:  make(map[string]*webhook.ApplicationTemplateWithLabels, 0),
   822  			ExpectedErrMessage:           "",
   823  		},
   824  		{
   825  			Name: "error when listing app template labels",
   826  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   827  				repo := &automock.ApplicationRepository{}
   828  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return([]*model.Application{fixApplicationModel(ApplicationID), fixApplicationModelWithoutTemplate(Application2ID)}, nil).Once()
   829  				return repo
   830  			},
   831  			ApplicationTemplateRepoFN: func() *automock.ApplicationTemplateRepository {
   832  				repo := &automock.ApplicationTemplateRepository{}
   833  				repo.On("ListByIDs", ctx, []string{ApplicationTemplateID}).Return([]*model.ApplicationTemplate{fixApplicationTemplateModel()}, nil).Once()
   834  				return repo
   835  			},
   836  			LabelRepoFN: func() *automock.LabelRepository {
   837  				repo := &automock.LabelRepository{}
   838  				repo.On("ListForObjectIDs", ctx, Tnt, model.ApplicationLabelableObject, mock.MatchedBy(func(ids []string) bool { return checkIfEqual(ids, []string{ApplicationID, Application2ID}) })).Return(map[string]map[string]interface{}{
   839  					ApplicationID:  fixApplicationLabelsMap(),
   840  					Application2ID: fixApplicationLabelsMap(),
   841  				}, nil).Once()
   842  				repo.On("ListForObjectIDs", ctx, Tnt, model.AppTemplateLabelableObject, []string{ApplicationTemplateID}).Return(nil, testErr).Once()
   843  				return repo
   844  			},
   845  			FormationName:      ScenarioName,
   846  			ExpectedErrMessage: "while listing labels for application templates",
   847  		},
   848  		{
   849  			Name: "error when listing app templates",
   850  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   851  				repo := &automock.ApplicationRepository{}
   852  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return([]*model.Application{fixApplicationModel(ApplicationID), fixApplicationModelWithoutTemplate(Application2ID)}, nil).Once()
   853  				return repo
   854  			},
   855  			ApplicationTemplateRepoFN: func() *automock.ApplicationTemplateRepository {
   856  				repo := &automock.ApplicationTemplateRepository{}
   857  				repo.On("ListByIDs", ctx, []string{ApplicationTemplateID}).Return(nil, testErr).Once()
   858  				return repo
   859  			},
   860  			LabelRepoFN: func() *automock.LabelRepository {
   861  				repo := &automock.LabelRepository{}
   862  				repo.On("ListForObjectIDs", ctx, Tnt, model.ApplicationLabelableObject, mock.MatchedBy(func(ids []string) bool { return checkIfEqual(ids, []string{ApplicationID, Application2ID}) })).Return(map[string]map[string]interface{}{
   863  					ApplicationID:  fixApplicationLabelsMap(),
   864  					Application2ID: fixApplicationLabelsMap(),
   865  				}, nil).Once()
   866  				return repo
   867  			},
   868  			FormationName:      ScenarioName,
   869  			ExpectedErrMessage: "while listing application templates",
   870  		},
   871  		{
   872  			Name: "error when listing application labels",
   873  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   874  				repo := &automock.ApplicationRepository{}
   875  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return([]*model.Application{fixApplicationModel(ApplicationID), fixApplicationModelWithoutTemplate(Application2ID)}, nil).Once()
   876  				return repo
   877  			},
   878  			LabelRepoFN: func() *automock.LabelRepository {
   879  				repo := &automock.LabelRepository{}
   880  				repo.On("ListForObjectIDs", ctx, Tnt, model.ApplicationLabelableObject, mock.MatchedBy(func(ids []string) bool { return checkIfEqual(ids, []string{ApplicationID, Application2ID}) })).Return(nil, testErr).Once()
   881  				return repo
   882  			},
   883  			FormationName:      ScenarioName,
   884  			ExpectedErrMessage: "while listing labels for applications",
   885  		},
   886  		{
   887  			Name: "error when listing application labels",
   888  			ApplicationRepoFN: func() *automock.ApplicationRepository {
   889  				repo := &automock.ApplicationRepository{}
   890  				repo.On("ListByScenariosNoPaging", ctx, Tnt, []string{ScenarioName}).Return(nil, testErr).Once()
   891  				return repo
   892  			},
   893  			FormationName:      ScenarioName,
   894  			ExpectedErrMessage: "while listing applications in formation",
   895  		},
   896  	}
   897  
   898  	for _, testCase := range testCases {
   899  		t.Run(testCase.Name, func(t *testing.T) {
   900  			// GIVEN
   901  			applicationRepo := unusedAppRepo()
   902  			if testCase.ApplicationRepoFN != nil {
   903  				applicationRepo = testCase.ApplicationRepoFN()
   904  			}
   905  			appTemplateRepo := unusedAppTemplateRepo()
   906  			if testCase.ApplicationTemplateRepoFN != nil {
   907  				appTemplateRepo = testCase.ApplicationTemplateRepoFN()
   908  			}
   909  			labelRepo := unusedLabelRepo()
   910  			if testCase.LabelRepoFN != nil {
   911  				labelRepo = testCase.LabelRepoFN()
   912  			}
   913  
   914  			webhookDataInputBuilder := databuilder.NewWebhookDataInputBuilder(applicationRepo, appTemplateRepo, nil, nil, labelRepo)
   915  
   916  			// WHEN
   917  			appMappings, appTemplateMappings, err := webhookDataInputBuilder.PrepareApplicationMappingsInFormation(emptyCtx, Tnt, testCase.FormationName)
   918  
   919  			// THEN
   920  			if testCase.ExpectedErrMessage == "" {
   921  				require.NoError(t, err)
   922  				assert.Equal(t, testCase.ExpectedApplicationsMappings, appMappings)
   923  				assert.Equal(t, testCase.ExpectedAppTemplateMappings, appTemplateMappings)
   924  			} else {
   925  				require.Error(t, err)
   926  				require.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   927  				require.Nil(t, appMappings, appTemplateMappings)
   928  			}
   929  
   930  			mock.AssertExpectationsForObjects(t, applicationRepo, appTemplateRepo, labelRepo)
   931  		})
   932  	}
   933  }
   934  
   935  func convertLabels(labels map[string]*model.Label) map[string]string {
   936  	convertedLabels := make(map[string]string, len(labels))
   937  	for _, l := range labels {
   938  		stringLabel, ok := l.Value.(string)
   939  		if !ok {
   940  			marshalled, err := json.Marshal(l.Value)
   941  			if err != nil {
   942  				return nil
   943  			}
   944  			stringLabel = string(marshalled)
   945  		}
   946  
   947  		convertedLabels[l.Key] = stringLabel
   948  	}
   949  	return convertedLabels
   950  }
   951  
   952  // helper func that checks if the elements of two slices are the same no matter their order
   953  func checkIfEqual(first, second []string) bool {
   954  	if len(first) != len(second) {
   955  		return false
   956  	}
   957  	exists := make(map[string]bool)
   958  	for _, value := range first {
   959  		exists[value] = true
   960  	}
   961  	for _, value := range second {
   962  		if !exists[value] {
   963  			return false
   964  		}
   965  	}
   966  	return true
   967  }
   968  
   969  func checkIfIDInSet(wh *model.Webhook, ids []string) bool {
   970  	for _, id := range ids {
   971  		if wh.ID == id {
   972  			return true
   973  		}
   974  	}
   975  	return false
   976  }