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

     1  package apptemplate_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
     9  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    10  
    11  	"github.com/kyma-incubator/compass/components/director/internal/labelfilter"
    12  
    13  	"github.com/kyma-incubator/compass/components/director/internal/domain/apptemplate"
    14  	"github.com/kyma-incubator/compass/components/director/internal/domain/apptemplate/automock"
    15  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    16  	"github.com/kyma-incubator/compass/components/director/internal/model"
    17  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/mock"
    20  
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestService_Create(t *testing.T) {
    27  	// GIVEN
    28  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
    29  
    30  	uidSvcFn := func() *automock.UIDService {
    31  		uidSvc := &automock.UIDService{}
    32  		uidSvc.On("Generate").Return(testID)
    33  		return uidSvc
    34  	}
    35  
    36  	predefinedID := "123-465-789"
    37  
    38  	appInputJSON := fmt.Sprintf(appInputJSONWithAppTypeLabelString, testName)
    39  	appInputJSONOtherSystemType := fmt.Sprintf(appInputJSONWithAppTypeLabelString, "random-name")
    40  
    41  	modelAppTemplate := fixModelAppTemplateWithAppInputJSON(testID, testName, appInputJSON, []*model.Webhook{})
    42  	modelAppTemplateOtherSystemType := fixModelAppTemplateWithAppInputJSON(testID, testNameOtherSystemType, appInputJSONOtherSystemType, []*model.Webhook{})
    43  
    44  	appTemplateInputWithWebhooks := fixModelAppTemplateInput(testName, appInputJSONString)
    45  	appTemplateInputWithWebhooks.Webhooks = []*model.WebhookInput{
    46  		{
    47  			Type: model.WebhookTypeConfigurationChanged,
    48  			URL:  str.Ptr("foourl"),
    49  			Auth: &model.AuthInput{},
    50  		},
    51  	}
    52  	appTemplateInputMatcher := func(webhooks []*model.Webhook) bool {
    53  		return len(webhooks) == 1 && webhooks[0].ObjectID == testID && webhooks[0].Type == model.WebhookTypeConfigurationChanged && *webhooks[0].URL == "foourl"
    54  	}
    55  
    56  	testCases := []struct {
    57  		Name              string
    58  		Input             func() *model.ApplicationTemplateInput
    59  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
    60  		WebhookRepoFn     func() *automock.WebhookRepository
    61  		LabelUpsertSvcFn  func() *automock.LabelUpsertService
    62  		LabelRepoFn       func() *automock.LabelRepository
    63  		ExpectedError     error
    64  		ExpectedOutput    string
    65  	}{
    66  		{
    67  			Name: "Success",
    68  			Input: func() *model.ApplicationTemplateInput {
    69  				return fixModelAppTemplateInput(testName, appInputJSON)
    70  			},
    71  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
    72  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
    73  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
    74  				appTemplateRepo.On("Create", ctx, *modelAppTemplate).Return(nil).Once()
    75  				return appTemplateRepo
    76  			},
    77  			WebhookRepoFn: func() *automock.WebhookRepository {
    78  				webhookRepo := &automock.WebhookRepository{}
    79  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
    80  				return webhookRepo
    81  			},
    82  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
    83  				labelUpsertService := &automock.LabelUpsertService{}
    84  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, "foo", map[string]interface{}{"test": "test"}).Return(nil).Once()
    85  				return labelUpsertService
    86  			},
    87  			LabelRepoFn:    UnusedLabelRepo,
    88  			ExpectedOutput: testID,
    89  		},
    90  		{
    91  			Name: "Success without app input labels",
    92  			Input: func() *model.ApplicationTemplateInput {
    93  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
    94  				return fixModelAppTemplateInput(testName, appInputJSON)
    95  			},
    96  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
    97  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
    98  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
    99  				appTemplateRepo.On("Create", ctx, mock.AnythingOfType("model.ApplicationTemplate")).Return(nil).Once()
   100  				return appTemplateRepo
   101  			},
   102  			WebhookRepoFn: func() *automock.WebhookRepository {
   103  				webhookRepo := &automock.WebhookRepository{}
   104  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
   105  				return webhookRepo
   106  			},
   107  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
   108  				labelUpsertService := &automock.LabelUpsertService{}
   109  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, "foo", map[string]interface{}{"test": "test"}).Return(nil).Once()
   110  				return labelUpsertService
   111  			},
   112  			LabelRepoFn:    UnusedLabelRepo,
   113  			ExpectedOutput: testID,
   114  		},
   115  		{
   116  			Name: "Success when ID is already generated",
   117  			Input: func() *model.ApplicationTemplateInput {
   118  				return fixModelAppTemplateWithIDInput(testName, appInputJSON, &predefinedID)
   119  			},
   120  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   121  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   122  				modelAppTemplateWithPredefinedID := *modelAppTemplate
   123  				modelAppTemplateWithPredefinedID.ID = predefinedID
   124  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   125  				appTemplateRepo.On("Create", ctx, modelAppTemplateWithPredefinedID).Return(nil).Once()
   126  				return appTemplateRepo
   127  			},
   128  			WebhookRepoFn: func() *automock.WebhookRepository {
   129  				webhookRepo := &automock.WebhookRepository{}
   130  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
   131  				return webhookRepo
   132  			},
   133  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
   134  				labelUpsertService := &automock.LabelUpsertService{}
   135  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, predefinedID, map[string]interface{}{"test": "test"}).Return(nil).Once()
   136  				return labelUpsertService
   137  			},
   138  			LabelRepoFn:    UnusedLabelRepo,
   139  			ExpectedOutput: predefinedID,
   140  		},
   141  		{
   142  			Name: "Success for Application Template with webhooks",
   143  			Input: func() *model.ApplicationTemplateInput {
   144  				return appTemplateInputWithWebhooks
   145  			},
   146  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   147  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   148  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   149  				appTemplateRepo.On("Create", ctx, mock.AnythingOfType("model.ApplicationTemplate")).Return(nil).Once()
   150  				return appTemplateRepo
   151  			},
   152  			WebhookRepoFn: func() *automock.WebhookRepository {
   153  				webhookRepo := &automock.WebhookRepository{}
   154  				webhookRepo.On("CreateMany", ctx, "", mock.MatchedBy(appTemplateInputMatcher)).Return(nil).Once()
   155  				return webhookRepo
   156  			},
   157  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
   158  				labelUpsertService := &automock.LabelUpsertService{}
   159  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, "foo", map[string]interface{}{"test": "test"}).Return(nil).Once()
   160  				return labelUpsertService
   161  			},
   162  			LabelRepoFn:    UnusedLabelRepo,
   163  			ExpectedOutput: testID,
   164  		},
   165  		{
   166  			Name: "Error when creating application template",
   167  			Input: func() *model.ApplicationTemplateInput {
   168  				return fixModelAppTemplateInput(testName, appInputJSON)
   169  			},
   170  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   171  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   172  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   173  				appTemplateRepo.On("Create", ctx, *modelAppTemplate).Return(testError).Once()
   174  				return appTemplateRepo
   175  			},
   176  			WebhookRepoFn:    UnusedWebhookRepo,
   177  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
   178  			LabelRepoFn:      UnusedLabelRepo,
   179  			ExpectedError:    testError,
   180  			ExpectedOutput:   "",
   181  		},
   182  		{
   183  			Name: "Error when checking application type label - labels are not map[string]interface{}",
   184  			Input: func() *model.ApplicationTemplateInput {
   185  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":123,"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
   186  				return fixModelAppTemplateInput(testName, appInputJSON)
   187  			},
   188  			AppTemplateRepoFn: UnusedAppTemplateRepo,
   189  			WebhookRepoFn:     UnusedWebhookRepo,
   190  			LabelUpsertSvcFn:  UnusedLabelUpsertSvc,
   191  			LabelRepoFn:       UnusedLabelRepo,
   192  			ExpectedError:     errors.New("app input json labels are type map[string]interface {} instead of map[string]interface{}"),
   193  		},
   194  		{
   195  			Name: "Error when checking application type label - application type is not string",
   196  			Input: func() *model.ApplicationTemplateInput {
   197  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":{"applicationType":123,"test":["val","val2"]},"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
   198  				return fixModelAppTemplateInput(testName, appInputJSON)
   199  			},
   200  			AppTemplateRepoFn: UnusedAppTemplateRepo,
   201  			WebhookRepoFn:     UnusedWebhookRepo,
   202  			LabelUpsertSvcFn:  UnusedLabelUpsertSvc,
   203  			LabelRepoFn:       UnusedLabelRepo,
   204  			ExpectedError:     errors.New("\"applicationType\" label value must be string"),
   205  		},
   206  		{
   207  			Name: "Error when checking application type label - application type does not match the application template name",
   208  			Input: func() *model.ApplicationTemplateInput {
   209  				return fixModelAppTemplateInput(testName, fmt.Sprintf(appInputJSONWithAppTypeLabelString, "random-name"))
   210  			},
   211  			AppTemplateRepoFn: UnusedAppTemplateRepo,
   212  			WebhookRepoFn:     UnusedWebhookRepo,
   213  			LabelUpsertSvcFn:  UnusedLabelUpsertSvc,
   214  			LabelRepoFn:       UnusedLabelRepo,
   215  			ExpectedError:     errors.New("\"applicationType\" label value does not match the application template name"),
   216  		},
   217  		{
   218  			Name: "No error when checking application type label - application type does not match the application template name",
   219  			Input: func() *model.ApplicationTemplateInput {
   220  				return fixModelAppTemplateInput(testNameOtherSystemType, fmt.Sprintf(appInputJSONWithAppTypeLabelString, "random-name"))
   221  			},
   222  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   223  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   224  				appTemplateRepo.On("ListByName", ctx, testNameOtherSystemType).Return([]*model.ApplicationTemplate{}, nil).Once()
   225  				appTemplateRepo.On("Create", ctx, *modelAppTemplateOtherSystemType).Return(nil).Once()
   226  				return appTemplateRepo
   227  			},
   228  			WebhookRepoFn: func() *automock.WebhookRepository {
   229  				webhookRepo := &automock.WebhookRepository{}
   230  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
   231  				return webhookRepo
   232  			},
   233  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
   234  				labelUpsertService := &automock.LabelUpsertService{}
   235  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, "foo", map[string]interface{}{"test": "test"}).Return(nil).Once()
   236  				return labelUpsertService
   237  			},
   238  			LabelRepoFn:    UnusedLabelRepo,
   239  			ExpectedOutput: testID,
   240  		},
   241  		{
   242  			Name: "Error when checking if application template already exists - GetByName returns error",
   243  			Input: func() *model.ApplicationTemplateInput {
   244  				return fixModelAppTemplateInput(testName, appInputJSONString)
   245  			},
   246  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   247  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   248  				appTemplateRepo.On("ListByName", ctx, testName).Return(nil, testError).Once()
   249  				return appTemplateRepo
   250  			},
   251  			WebhookRepoFn:    UnusedWebhookRepo,
   252  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
   253  			LabelRepoFn:      UnusedLabelRepo,
   254  			ExpectedError:    testError,
   255  		},
   256  		{
   257  			Name: "Error when application template already exists",
   258  			Input: func() *model.ApplicationTemplateInput {
   259  				return fixModelAppTemplateInput(testName, appInputJSONString)
   260  			},
   261  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   262  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   263  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{modelAppTemplate}, nil).Once()
   264  				return appTemplateRepo
   265  			},
   266  			WebhookRepoFn:    UnusedWebhookRepo,
   267  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
   268  			LabelRepoFn: func() *automock.LabelRepository {
   269  				labelRepo := &automock.LabelRepository{}
   270  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
   271  				return labelRepo
   272  			},
   273  			ExpectedError: errors.New("application template with name \"bar\" and region <nil> already exists"),
   274  		},
   275  		{
   276  			Name: "Error when creating webhooks",
   277  			Input: func() *model.ApplicationTemplateInput {
   278  				return fixModelAppTemplateInput(testName, appInputJSON)
   279  			},
   280  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   281  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   282  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   283  				appTemplateRepo.On("Create", ctx, *modelAppTemplate).Return(nil).Once()
   284  				return appTemplateRepo
   285  			},
   286  			WebhookRepoFn: func() *automock.WebhookRepository {
   287  				webhookRepo := &automock.WebhookRepository{}
   288  				webhookRepo.On("CreateMany", ctx, "", mock.AnythingOfType("[]*model.Webhook")).Return(testError).Once()
   289  				return webhookRepo
   290  			},
   291  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
   292  			LabelRepoFn:      UnusedLabelRepo,
   293  			ExpectedError:    testError,
   294  		},
   295  	}
   296  
   297  	for _, testCase := range testCases {
   298  		t.Run(testCase.Name, func(t *testing.T) {
   299  			appTemplateRepo := testCase.AppTemplateRepoFn()
   300  			webhookRepo := testCase.WebhookRepoFn()
   301  			labelUpsertSvc := testCase.LabelUpsertSvcFn()
   302  			labelRepo := testCase.LabelRepoFn()
   303  			idSvc := uidSvcFn()
   304  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, idSvc, labelUpsertSvc, labelRepo, nil)
   305  
   306  			// WHEN
   307  			result, err := svc.Create(ctx, *testCase.Input())
   308  
   309  			// THEN
   310  			if testCase.ExpectedError != nil {
   311  				require.Error(t, err)
   312  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   313  			} else {
   314  				assert.NoError(t, err)
   315  			}
   316  			assert.Equal(t, testCase.ExpectedOutput, result)
   317  
   318  			appTemplateRepo.AssertExpectations(t)
   319  			labelUpsertSvc.AssertExpectations(t)
   320  			labelRepo.AssertExpectations(t)
   321  			idSvc.AssertExpectations(t)
   322  		})
   323  	}
   324  }
   325  
   326  func TestService_CreateWithLabels(t *testing.T) {
   327  	// GIVEN
   328  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   329  
   330  	uidSvcFn := func() *automock.UIDService {
   331  		uidSvc := &automock.UIDService{}
   332  		uidSvc.On("Generate").Return(testID)
   333  		return uidSvc
   334  	}
   335  
   336  	appInputJSON := fmt.Sprintf(appInputJSONWithAppTypeLabelString, testName)
   337  	modelAppTemplate := fixModelAppTemplateWithAppInputJSON(testID, testName, appInputJSON, []*model.Webhook{})
   338  
   339  	testCases := []struct {
   340  		Name              string
   341  		Input             *model.ApplicationTemplateInput
   342  		AppTemplateID     string
   343  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   344  		WebhookRepoFn     func() *automock.WebhookRepository
   345  		LabelUpsertSvcFn  func() *automock.LabelUpsertService
   346  		ExpectedError     error
   347  		ExpectedOutput    string
   348  	}{
   349  		{
   350  			Name:  "Success",
   351  			Input: fixModelAppTemplateInput(testName, appInputJSON),
   352  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   353  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   354  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   355  				appTemplateRepo.On("Create", ctx, *modelAppTemplate).Return(nil).Once()
   356  				return appTemplateRepo
   357  			},
   358  			WebhookRepoFn: func() *automock.WebhookRepository {
   359  				webhookRepo := &automock.WebhookRepository{}
   360  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
   361  				return webhookRepo
   362  			},
   363  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
   364  				labelUpsertService := &automock.LabelUpsertService{}
   365  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, "foo", map[string]interface{}{"createWithLabels": "OK", "test": "test"}).Return(nil).Once()
   366  				return labelUpsertService
   367  			},
   368  			ExpectedError:  nil,
   369  			ExpectedOutput: testID,
   370  		},
   371  		{
   372  			Name:  "Error when creating application template",
   373  			Input: fixModelAppTemplateInput(testName, appInputJSON),
   374  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   375  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   376  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   377  				appTemplateRepo.On("Create", ctx, *modelAppTemplate).Return(testError).Once()
   378  				return appTemplateRepo
   379  			},
   380  			WebhookRepoFn:    UnusedWebhookRepo,
   381  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
   382  			ExpectedError:    testError,
   383  			ExpectedOutput:   "",
   384  		},
   385  	}
   386  
   387  	for _, testCase := range testCases {
   388  		t.Run(testCase.Name, func(t *testing.T) {
   389  			appTemplateRepo := testCase.AppTemplateRepoFn()
   390  			webhookRepo := testCase.WebhookRepoFn()
   391  			labelUpsertSvc := testCase.LabelUpsertSvcFn()
   392  			idSvc := uidSvcFn()
   393  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, idSvc, labelUpsertSvc, nil, nil)
   394  
   395  			defer mock.AssertExpectationsForObjects(t, appTemplateRepo, labelUpsertSvc, idSvc)
   396  
   397  			// WHEN
   398  			result, err := svc.CreateWithLabels(ctx, *testCase.Input, map[string]interface{}{"createWithLabels": "OK"})
   399  
   400  			// THEN
   401  			if testCase.ExpectedError != nil {
   402  				require.Error(t, err)
   403  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   404  			} else {
   405  				assert.NoError(t, err)
   406  			}
   407  			assert.Equal(t, testCase.ExpectedOutput, result)
   408  		})
   409  	}
   410  }
   411  
   412  func TestService_Get(t *testing.T) {
   413  	// GIVEN
   414  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   415  
   416  	modelAppTemplate := fixModelApplicationTemplate(testID, testName, fixModelApplicationTemplateWebhooks(testWebhookID, testID))
   417  
   418  	testCases := []struct {
   419  		Name              string
   420  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   421  		WebhookRepoFn     func() *automock.WebhookRepository
   422  		ExpectedError     error
   423  		ExpectedOutput    *model.ApplicationTemplate
   424  	}{
   425  		{
   426  			Name: "Success",
   427  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   428  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   429  				appTemplateRepo.On("Get", ctx, testID).Return(modelAppTemplate, nil).Once()
   430  				return appTemplateRepo
   431  			},
   432  			WebhookRepoFn:  UnusedWebhookRepo,
   433  			ExpectedOutput: modelAppTemplate,
   434  		},
   435  		{
   436  			Name: "Error when getting application template",
   437  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   438  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   439  				appTemplateRepo.On("Get", ctx, testID).Return(nil, testError).Once()
   440  				return appTemplateRepo
   441  			},
   442  			WebhookRepoFn: UnusedWebhookRepo,
   443  			ExpectedError: testError,
   444  		},
   445  	}
   446  
   447  	for _, testCase := range testCases {
   448  		t.Run(testCase.Name, func(t *testing.T) {
   449  			appTemplateRepo := testCase.AppTemplateRepoFn()
   450  			webhookRepo := testCase.WebhookRepoFn()
   451  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, nil, nil, nil, nil)
   452  
   453  			// WHEN
   454  			result, err := svc.Get(ctx, testID)
   455  
   456  			// THEN
   457  			if testCase.ExpectedError != nil {
   458  				require.Error(t, err)
   459  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   460  			} else {
   461  				assert.NoError(t, err)
   462  			}
   463  			assert.Equal(t, testCase.ExpectedOutput, result)
   464  
   465  			appTemplateRepo.AssertExpectations(t)
   466  		})
   467  	}
   468  }
   469  
   470  func TestService_ListLabels(t *testing.T) {
   471  	// GIVEN
   472  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   473  
   474  	modelAppTemplate := fixModelApplicationTemplate(testID, testName, fixModelApplicationTemplateWebhooks(testWebhookID, testID))
   475  
   476  	id := "foo"
   477  	labelKey1 := "key1"
   478  	labelValue1 := "val1"
   479  	labelKey2 := "key2"
   480  	labelValue2 := "val2"
   481  	labels := map[string]*model.Label{
   482  		"abc": {
   483  			ID:         "abc",
   484  			Tenant:     str.Ptr(testTenant),
   485  			Key:        labelKey1,
   486  			Value:      labelValue1,
   487  			ObjectID:   id,
   488  			ObjectType: model.AppTemplateLabelableObject,
   489  		},
   490  		"def": {
   491  			ID:         "def",
   492  			Tenant:     str.Ptr(testTenant),
   493  			Key:        labelKey2,
   494  			Value:      labelValue2,
   495  			ObjectID:   id,
   496  			ObjectType: model.AppTemplateLabelableObject,
   497  		},
   498  	}
   499  
   500  	testCases := []struct {
   501  		Name              string
   502  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   503  		LabelRepoFn       func() *automock.LabelRepository
   504  		ExpectedError     error
   505  		ExpectedOutput    *model.ApplicationTemplate
   506  	}{
   507  		{
   508  			Name: "Success",
   509  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   510  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   511  				appTemplateRepo.On("Exists", ctx, testID).Return(true, nil).Once()
   512  				return appTemplateRepo
   513  			},
   514  			LabelRepoFn: func() *automock.LabelRepository {
   515  				labelRepo := &automock.LabelRepository{}
   516  				labelRepo.On("ListForGlobalObject", ctx, model.AppTemplateLabelableObject, testID).Return(labels, nil).Once()
   517  				return labelRepo
   518  			},
   519  			ExpectedOutput: modelAppTemplate,
   520  		},
   521  		{
   522  			Name: "Error when listing labels",
   523  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   524  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   525  				appTemplateRepo.On("Exists", ctx, testID).Return(true, nil).Once()
   526  				return appTemplateRepo
   527  			},
   528  			LabelRepoFn: func() *automock.LabelRepository {
   529  				labelRepo := &automock.LabelRepository{}
   530  				labelRepo.On("ListForGlobalObject", ctx, model.AppTemplateLabelableObject, testID).Return(nil, testError).Once()
   531  				return labelRepo
   532  			},
   533  			ExpectedError: testError,
   534  		},
   535  		{
   536  			Name: "Error when checking app template existence",
   537  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   538  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   539  				appTemplateRepo.On("Exists", ctx, testID).Return(false, testError).Once()
   540  				return appTemplateRepo
   541  			},
   542  			LabelRepoFn:   UnusedLabelRepo,
   543  			ExpectedError: testError,
   544  		},
   545  		{
   546  			Name: "Error when app template does not exists",
   547  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   548  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   549  				appTemplateRepo.On("Exists", ctx, testID).Return(false, nil).Once()
   550  				return appTemplateRepo
   551  			},
   552  			LabelRepoFn:   UnusedLabelRepo,
   553  			ExpectedError: errors.New("application template with ID foo doesn't exist"),
   554  		},
   555  	}
   556  
   557  	for _, testCase := range testCases {
   558  		t.Run(testCase.Name, func(t *testing.T) {
   559  			appTemplateRepo := testCase.AppTemplateRepoFn()
   560  			labelRepo := testCase.LabelRepoFn()
   561  			svc := apptemplate.NewService(appTemplateRepo, nil, nil, nil, labelRepo, nil)
   562  
   563  			// WHEN
   564  			result, err := svc.ListLabels(ctx, testID)
   565  
   566  			// THEN
   567  			if testCase.ExpectedError != nil {
   568  				require.Error(t, err)
   569  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   570  			} else {
   571  				assert.NoError(t, err)
   572  				assert.Equal(t, labels, result)
   573  			}
   574  
   575  			appTemplateRepo.AssertExpectations(t)
   576  			labelRepo.AssertExpectations(t)
   577  		})
   578  	}
   579  }
   580  
   581  func TestService_GetLabel(t *testing.T) {
   582  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   583  
   584  	id := "foo"
   585  	labelKey1 := "key1"
   586  	labelValue1 := "val1"
   587  	labels := map[string]*model.Label{
   588  		"abc": {
   589  			ID:         "abc",
   590  			Tenant:     str.Ptr(testTenant),
   591  			Key:        labelKey1,
   592  			Value:      labelValue1,
   593  			ObjectID:   id,
   594  			ObjectType: model.AppTemplateLabelableObject,
   595  		},
   596  	}
   597  
   598  	testCases := []struct {
   599  		Name              string
   600  		Key               string
   601  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   602  		LabelRepoFn       func() *automock.LabelRepository
   603  		ExpectedError     error
   604  		ExpectedOutput    *model.Label
   605  	}{
   606  		{
   607  			Name: "Success",
   608  			Key:  "abc",
   609  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   610  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   611  				appTemplateRepo.On("Exists", ctx, testID).Return(true, nil).Once()
   612  				return appTemplateRepo
   613  			},
   614  			LabelRepoFn: func() *automock.LabelRepository {
   615  				labelRepo := &automock.LabelRepository{}
   616  				labelRepo.On("ListForGlobalObject", ctx, model.AppTemplateLabelableObject, testID).Return(labels, nil).Once()
   617  				return labelRepo
   618  			},
   619  			ExpectedOutput: labels["abc"],
   620  			ExpectedError:  nil,
   621  		},
   622  		{
   623  			Name: "Error when listing labels",
   624  			Key:  "abc",
   625  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   626  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   627  				appTemplateRepo.On("Exists", ctx, testID).Return(true, nil).Once()
   628  				return appTemplateRepo
   629  			},
   630  			LabelRepoFn: func() *automock.LabelRepository {
   631  				labelRepo := &automock.LabelRepository{}
   632  				labelRepo.On("ListForGlobalObject", ctx, model.AppTemplateLabelableObject, testID).Return(nil, testError).Once()
   633  				return labelRepo
   634  			},
   635  			ExpectedOutput: nil,
   636  			ExpectedError:  testError,
   637  		},
   638  		{
   639  			Name: "Error when checking label with key",
   640  			Key:  "fake-key",
   641  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   642  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   643  				appTemplateRepo.On("Exists", ctx, testID).Return(true, nil).Once()
   644  				return appTemplateRepo
   645  			},
   646  			LabelRepoFn: func() *automock.LabelRepository {
   647  				labelRepo := &automock.LabelRepository{}
   648  				labelRepo.On("ListForGlobalObject", ctx, model.AppTemplateLabelableObject, testID).Return(labels, nil).Once()
   649  				return labelRepo
   650  			},
   651  			ExpectedOutput: nil,
   652  			ExpectedError:  fmt.Errorf("label fake-key for application template with ID %s doesn't exist", testID),
   653  		},
   654  	}
   655  
   656  	for _, testCase := range testCases {
   657  		t.Run(testCase.Name, func(t *testing.T) {
   658  			appTemplateRepo := testCase.AppTemplateRepoFn()
   659  			labelRepo := testCase.LabelRepoFn()
   660  			svc := apptemplate.NewService(appTemplateRepo, nil, nil, nil, labelRepo, nil)
   661  
   662  			// WHEN
   663  			result, err := svc.GetLabel(ctx, testID, testCase.Key)
   664  
   665  			// THEN
   666  			if testCase.ExpectedError != nil {
   667  				require.Error(t, err)
   668  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   669  			} else {
   670  				assert.NoError(t, err)
   671  				assert.Equal(t, testCase.ExpectedOutput, result)
   672  			}
   673  
   674  			appTemplateRepo.AssertExpectations(t)
   675  			labelRepo.AssertExpectations(t)
   676  		})
   677  	}
   678  }
   679  
   680  func TestService_ListByName(t *testing.T) {
   681  	// GIVEN
   682  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   683  
   684  	modelAppTemplates := []*model.ApplicationTemplate{fixModelApplicationTemplate(testID, testName, fixModelApplicationTemplateWebhooks(testWebhookID, testID))}
   685  
   686  	testCases := []struct {
   687  		Name              string
   688  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   689  		ExpectedError     error
   690  		ExpectedOutput    []*model.ApplicationTemplate
   691  	}{
   692  		{
   693  			Name: "Success",
   694  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   695  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   696  				appTemplateRepo.On("ListByName", ctx, testName).Return(modelAppTemplates, nil).Once()
   697  				return appTemplateRepo
   698  			},
   699  			ExpectedOutput: modelAppTemplates,
   700  		},
   701  		{
   702  			Name: "Error when getting application template",
   703  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   704  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   705  				appTemplateRepo.On("ListByName", ctx, testName).Return(nil, testError).Once()
   706  				return appTemplateRepo
   707  			},
   708  			ExpectedError: testError,
   709  		},
   710  	}
   711  
   712  	for _, testCase := range testCases {
   713  		t.Run(testCase.Name, func(t *testing.T) {
   714  			appTemplateRepo := testCase.AppTemplateRepoFn()
   715  			svc := apptemplate.NewService(appTemplateRepo, nil, nil, nil, nil, nil)
   716  
   717  			// WHEN
   718  			result, err := svc.ListByName(ctx, testName)
   719  
   720  			// THEN
   721  			if testCase.ExpectedError != nil {
   722  				require.Error(t, err)
   723  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   724  			} else {
   725  				assert.NoError(t, err)
   726  			}
   727  			assert.Equal(t, testCase.ExpectedOutput, result)
   728  
   729  			appTemplateRepo.AssertExpectations(t)
   730  		})
   731  	}
   732  }
   733  
   734  func TestService_ListByFilters(t *testing.T) {
   735  	// GIVEN
   736  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   737  
   738  	modelAppTemplate := fixModelApplicationTemplate(testID, testName, fixModelApplicationTemplateWebhooks(testWebhookID, testID))
   739  	filters := []*labelfilter.LabelFilter{labelfilter.NewForKey("someKey")}
   740  
   741  	testCases := []struct {
   742  		Name              string
   743  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   744  		ExpectedError     error
   745  		ExpectedOutput    []*model.ApplicationTemplate
   746  	}{
   747  		{
   748  			Name: "Success",
   749  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   750  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   751  				appTemplateRepo.On("ListByFilters", ctx, filters).Return([]*model.ApplicationTemplate{modelAppTemplate}, nil).Once()
   752  				return appTemplateRepo
   753  			},
   754  			ExpectedOutput: []*model.ApplicationTemplate{modelAppTemplate},
   755  		},
   756  		{
   757  			Name: "Error when listing application templates by filters",
   758  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   759  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   760  				appTemplateRepo.On("ListByFilters", ctx, filters).Return(nil, testError).Once()
   761  				return appTemplateRepo
   762  			},
   763  			ExpectedError: testError,
   764  		},
   765  	}
   766  
   767  	for _, testCase := range testCases {
   768  		t.Run(testCase.Name, func(t *testing.T) {
   769  			appTemplateRepo := testCase.AppTemplateRepoFn()
   770  			svc := apptemplate.NewService(appTemplateRepo, nil, nil, nil, nil, nil)
   771  
   772  			// WHEN
   773  			result, err := svc.ListByFilters(ctx, filters)
   774  
   775  			// THEN
   776  			if testCase.ExpectedError != nil {
   777  				require.Error(t, err)
   778  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   779  			} else {
   780  				assert.NoError(t, err)
   781  			}
   782  			assert.Equal(t, testCase.ExpectedOutput, result)
   783  
   784  			appTemplateRepo.AssertExpectations(t)
   785  		})
   786  	}
   787  }
   788  
   789  func TestService_GetByNameAndRegion(t *testing.T) {
   790  	// GIVEN
   791  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   792  	modelAppTemplate := fixModelApplicationTemplate(testID, testName, fixModelApplicationTemplateWebhooks(testWebhookID, testID))
   793  	modelAppTemplates := []*model.ApplicationTemplate{modelAppTemplate}
   794  
   795  	testCases := []struct {
   796  		Name              string
   797  		Region            interface{}
   798  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   799  		LabelRepoFn       func() *automock.LabelRepository
   800  		ExpectedError     error
   801  		ExpectedOutput    *model.ApplicationTemplate
   802  	}{
   803  		{
   804  			Name:   "Success",
   805  			Region: nil,
   806  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   807  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   808  				appTemplateRepo.On("ListByName", ctx, testName).Return(modelAppTemplates, nil).Once()
   809  				return appTemplateRepo
   810  			},
   811  			LabelRepoFn: func() *automock.LabelRepository {
   812  				labelRepo := &automock.LabelRepository{}
   813  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
   814  				return labelRepo
   815  			},
   816  			ExpectedOutput: modelAppTemplate,
   817  		},
   818  		{
   819  			Name:   "Success with region",
   820  			Region: "eu-1",
   821  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   822  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   823  				appTemplateRepo.On("ListByName", ctx, testName).Return(modelAppTemplates, nil).Once()
   824  				return appTemplateRepo
   825  			},
   826  			LabelRepoFn: func() *automock.LabelRepository {
   827  				labelRepo := &automock.LabelRepository{}
   828  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(&model.Label{Value: "eu-1"}, nil).Once()
   829  				return labelRepo
   830  			},
   831  			ExpectedOutput: modelAppTemplate,
   832  		},
   833  		{
   834  			Name:   "Error when getting application templates by name",
   835  			Region: nil,
   836  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   837  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   838  				appTemplateRepo.On("ListByName", ctx, testName).Return(nil, testError).Once()
   839  				return appTemplateRepo
   840  			},
   841  			LabelRepoFn:   UnusedLabelRepo,
   842  			ExpectedError: testError,
   843  		},
   844  		{
   845  			Name:   "Error when retrieving region label",
   846  			Region: nil,
   847  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   848  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   849  				appTemplateRepo.On("ListByName", ctx, testName).Return(modelAppTemplates, nil).Once()
   850  				return appTemplateRepo
   851  			},
   852  			LabelRepoFn: func() *automock.LabelRepository {
   853  				labelRepo := &automock.LabelRepository{}
   854  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, testError).Once()
   855  				return labelRepo
   856  			},
   857  			ExpectedError: testError,
   858  		},
   859  		{
   860  			Name:   "Error when application template not found",
   861  			Region: nil,
   862  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   863  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   864  				appTemplateRepo.On("ListByName", ctx, testName).Return([]*model.ApplicationTemplate{}, nil).Once()
   865  				return appTemplateRepo
   866  			},
   867  			LabelRepoFn:   UnusedLabelRepo,
   868  			ExpectedError: apperrors.NewNotFoundErrorWithType(resource.ApplicationTemplate),
   869  		},
   870  	}
   871  
   872  	for _, testCase := range testCases {
   873  		t.Run(testCase.Name, func(t *testing.T) {
   874  			appTemplateRepo := testCase.AppTemplateRepoFn()
   875  			labelRepo := testCase.LabelRepoFn()
   876  			svc := apptemplate.NewService(appTemplateRepo, nil, nil, nil, labelRepo, nil)
   877  
   878  			// WHEN
   879  			result, err := svc.GetByNameAndRegion(ctx, testName, testCase.Region)
   880  
   881  			// THEN
   882  			if testCase.ExpectedError != nil {
   883  				require.Error(t, err)
   884  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   885  			} else {
   886  				assert.NoError(t, err)
   887  			}
   888  			assert.Equal(t, testCase.ExpectedOutput, result)
   889  
   890  			appTemplateRepo.AssertExpectations(t)
   891  			labelRepo.AssertExpectations(t)
   892  		})
   893  	}
   894  }
   895  
   896  func TestService_GetByFilters(t *testing.T) {
   897  	// GIVEN
   898  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   899  
   900  	modelAppTemplate := fixModelApplicationTemplate(testID, testName, fixModelApplicationTemplateWebhooks(testWebhookID, testID))
   901  	filters := []*labelfilter.LabelFilter{labelfilter.NewForKey("someKey")}
   902  
   903  	testCases := []struct {
   904  		Name              string
   905  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   906  		ExpectedError     error
   907  		ExpectedOutput    *model.ApplicationTemplate
   908  	}{
   909  		{
   910  			Name: "Success",
   911  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   912  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   913  				appTemplateRepo.On("GetByFilters", ctx, filters).Return(modelAppTemplate, nil).Once()
   914  				return appTemplateRepo
   915  			},
   916  			ExpectedOutput: modelAppTemplate,
   917  		},
   918  		{
   919  			Name: "Error when getting application template",
   920  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   921  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   922  				appTemplateRepo.On("GetByFilters", ctx, filters).Return(nil, testError).Once()
   923  				return appTemplateRepo
   924  			},
   925  			ExpectedError: testError,
   926  		},
   927  	}
   928  
   929  	for _, testCase := range testCases {
   930  		t.Run(testCase.Name, func(t *testing.T) {
   931  			appTemplateRepo := testCase.AppTemplateRepoFn()
   932  			svc := apptemplate.NewService(appTemplateRepo, nil, nil, nil, nil, nil)
   933  
   934  			// WHEN
   935  			result, err := svc.GetByFilters(ctx, filters)
   936  
   937  			// THEN
   938  			if testCase.ExpectedError != nil {
   939  				require.Error(t, err)
   940  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   941  			} else {
   942  				assert.NoError(t, err)
   943  			}
   944  			assert.Equal(t, testCase.ExpectedOutput, result)
   945  
   946  			appTemplateRepo.AssertExpectations(t)
   947  		})
   948  	}
   949  }
   950  
   951  func TestService_Exists(t *testing.T) {
   952  	// GIVEN
   953  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   954  
   955  	testCases := []struct {
   956  		Name              string
   957  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
   958  		WebhookRepoFn     func() *automock.WebhookRepository
   959  		ExpectedError     error
   960  		ExpectedOutput    bool
   961  	}{
   962  		{
   963  			Name: "Success",
   964  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   965  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   966  				appTemplateRepo.On("Exists", ctx, testID).Return(true, nil).Once()
   967  				return appTemplateRepo
   968  			},
   969  			WebhookRepoFn:  UnusedWebhookRepo,
   970  			ExpectedOutput: true,
   971  		},
   972  		{
   973  			Name: "Error when getting application template",
   974  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   975  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   976  				appTemplateRepo.On("Exists", ctx, testID).Return(false, testError).Once()
   977  				return appTemplateRepo
   978  			},
   979  			WebhookRepoFn:  UnusedWebhookRepo,
   980  			ExpectedError:  testError,
   981  			ExpectedOutput: false,
   982  		},
   983  	}
   984  
   985  	for _, testCase := range testCases {
   986  		t.Run(testCase.Name, func(t *testing.T) {
   987  			appTemplateRepo := testCase.AppTemplateRepoFn()
   988  			webhookRepo := testCase.WebhookRepoFn()
   989  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, nil, nil, nil, nil)
   990  
   991  			// WHEN
   992  			result, err := svc.Exists(ctx, testID)
   993  
   994  			// THEN
   995  			if testCase.ExpectedError != nil {
   996  				require.Error(t, err)
   997  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   998  			} else {
   999  				assert.NoError(t, err)
  1000  			}
  1001  			assert.Equal(t, testCase.ExpectedOutput, result)
  1002  
  1003  			appTemplateRepo.AssertExpectations(t)
  1004  		})
  1005  	}
  1006  }
  1007  
  1008  func TestService_List(t *testing.T) {
  1009  	// GIVEN
  1010  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
  1011  	modelAppTemplate := fixModelAppTemplatePage([]*model.ApplicationTemplate{
  1012  		fixModelApplicationTemplate("foo1", "bar1", fixModelApplicationTemplateWebhooks("webhook-id-1", "foo1")),
  1013  		fixModelApplicationTemplate("foo2", "bar2", fixModelApplicationTemplateWebhooks("webhook-id-2", "foo2")),
  1014  	})
  1015  	labelFilters := []*labelfilter.LabelFilter{labelfilter.NewForKeyWithQuery(RegionKey, "eu-1")}
  1016  
  1017  	testCases := []struct {
  1018  		Name              string
  1019  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
  1020  		WebhookRepoFn     func() *automock.WebhookRepository
  1021  		InputPageSize     int
  1022  		ExpectedError     error
  1023  		ExpectedOutput    model.ApplicationTemplatePage
  1024  	}{
  1025  		{
  1026  			Name: "Success",
  1027  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1028  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1029  				appTemplateRepo.On("List", ctx, labelFilters, 50, testCursor).Return(modelAppTemplate, nil).Once()
  1030  				return appTemplateRepo
  1031  			},
  1032  			WebhookRepoFn:  UnusedWebhookRepo,
  1033  			InputPageSize:  50,
  1034  			ExpectedOutput: modelAppTemplate,
  1035  		},
  1036  		{
  1037  			Name: "Error when listing application template",
  1038  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1039  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1040  				appTemplateRepo.On("List", ctx, labelFilters, 50, testCursor).Return(model.ApplicationTemplatePage{}, testError).Once()
  1041  				return appTemplateRepo
  1042  			},
  1043  			WebhookRepoFn:  UnusedWebhookRepo,
  1044  			InputPageSize:  50,
  1045  			ExpectedError:  testError,
  1046  			ExpectedOutput: model.ApplicationTemplatePage{},
  1047  		},
  1048  		{
  1049  			Name: "Error when page size too small",
  1050  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1051  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1052  				return appTemplateRepo
  1053  			},
  1054  			WebhookRepoFn:  UnusedWebhookRepo,
  1055  			InputPageSize:  0,
  1056  			ExpectedError:  errors.New("page size must be between 1 and 200"),
  1057  			ExpectedOutput: model.ApplicationTemplatePage{},
  1058  		},
  1059  		{
  1060  			Name: "Error when page size too big",
  1061  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1062  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1063  				return appTemplateRepo
  1064  			},
  1065  			WebhookRepoFn:  UnusedWebhookRepo,
  1066  			InputPageSize:  201,
  1067  			ExpectedError:  errors.New("page size must be between 1 and 200"),
  1068  			ExpectedOutput: model.ApplicationTemplatePage{},
  1069  		},
  1070  	}
  1071  
  1072  	for _, testCase := range testCases {
  1073  		t.Run(testCase.Name, func(t *testing.T) {
  1074  			appTemplateRepo := testCase.AppTemplateRepoFn()
  1075  			webhookRepo := testCase.WebhookRepoFn()
  1076  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, nil, nil, nil, nil)
  1077  
  1078  			// WHEN
  1079  			result, err := svc.List(ctx, labelFilters, testCase.InputPageSize, testCursor)
  1080  
  1081  			// THEN
  1082  			if testCase.ExpectedError != nil {
  1083  				require.Error(t, err)
  1084  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1085  			} else {
  1086  				assert.NoError(t, err)
  1087  			}
  1088  			assert.Equal(t, testCase.ExpectedOutput, result)
  1089  
  1090  			appTemplateRepo.AssertExpectations(t)
  1091  		})
  1092  	}
  1093  }
  1094  
  1095  func TestService_Update(t *testing.T) {
  1096  	// GIVEN
  1097  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
  1098  	appInputJSON := fmt.Sprintf(appInputJSONWithAppTypeLabelString, testName)
  1099  	appInputJSONWithNewAppType := fmt.Sprintf(appInputJSONWithAppTypeLabelString, updatedAppTemplateTestName)
  1100  
  1101  	modelAppTemplate := fixModelAppTemplateWithAppInputJSON(testID, testName, appInputJSON, nil)
  1102  	modelAppTemplateWithNewName := fixModelAppTemplateWithAppInputJSON(testID, updatedAppTemplateTestName, appInputJSONWithNewAppType, []*model.Webhook{})
  1103  	modelAppTemplateOtherSystemType := fixModelAppTemplateWithAppInputJSON(testID, testNameOtherSystemType, appInputJSON, nil)
  1104  	modelAppTemplateWithLabels := fixModelAppTemplateWithAppInputJSONAndLabels(testID, testName, appInputJSON, []*model.Webhook{}, newTestLabels)
  1105  	modelAppTemplateUpdateInput := fixModelAppTemplateUpdateInputWithLabels(testName, appInputJSON, newTestLabels)
  1106  
  1107  	modelApplicationFromTemplate := fixModelApplication(testAppID, testAppName)
  1108  	modelLabelInput := fixLabelInput(testLabelInputKey, updatedAppTemplateTestName, testAppID, model.ApplicationLabelableObject)
  1109  
  1110  	testCases := []struct {
  1111  		Name              string
  1112  		Input             func() *model.ApplicationTemplateUpdateInput
  1113  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
  1114  		WebhookRepoFn     func() *automock.WebhookRepository
  1115  		LabelUpsertSvcFn  func() *automock.LabelUpsertService
  1116  		LabelRepoFn       func() *automock.LabelRepository
  1117  		AppRepoFn         func() *automock.ApplicationRepository
  1118  		ExpectedError     error
  1119  	}{
  1120  		{
  1121  			Name: "Success",
  1122  			Input: func() *model.ApplicationTemplateUpdateInput {
  1123  				return modelAppTemplateUpdateInput
  1124  			},
  1125  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1126  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1127  				appTemplateRepo.On("Get", ctx, modelAppTemplateWithLabels.ID).Return(modelAppTemplateWithLabels, nil).Once()
  1128  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithLabels).Return(nil).Once()
  1129  				return appTemplateRepo
  1130  			},
  1131  			WebhookRepoFn: func() *automock.WebhookRepository {
  1132  				webhookRepo := &automock.WebhookRepository{}
  1133  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1134  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1135  				return webhookRepo
  1136  			},
  1137  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1138  				labelUpsertService := &automock.LabelUpsertService{}
  1139  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, modelAppTemplateUpdateInput.Labels).Return(nil).Once()
  1140  				return labelUpsertService
  1141  			},
  1142  			LabelRepoFn: func() *automock.LabelRepository {
  1143  				labelRepo := &automock.LabelRepository{}
  1144  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1145  				return labelRepo
  1146  			},
  1147  			AppRepoFn: UnusedAppRepo,
  1148  		},
  1149  		{
  1150  			Name: "Success - app input json without labels",
  1151  			Input: func() *model.ApplicationTemplateUpdateInput {
  1152  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
  1153  				return fixModelAppTemplateUpdateInput(testName, appInputJSON)
  1154  			},
  1155  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1156  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1157  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1158  				appTemplateRepo.On("Update", ctx, mock.AnythingOfType("model.ApplicationTemplate")).Return(nil).Once()
  1159  				return appTemplateRepo
  1160  			},
  1161  			WebhookRepoFn: func() *automock.WebhookRepository {
  1162  				webhookRepo := &automock.WebhookRepository{}
  1163  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1164  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1165  				return webhookRepo
  1166  			},
  1167  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1168  				labelUpsertService := &automock.LabelUpsertService{}
  1169  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, mock.Anything).Return(nil).Once()
  1170  				return labelUpsertService
  1171  			},
  1172  			LabelRepoFn: func() *automock.LabelRepository {
  1173  				labelRepo := &automock.LabelRepository{}
  1174  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1175  				return labelRepo
  1176  			},
  1177  			AppRepoFn: UnusedAppRepo,
  1178  		},
  1179  		{
  1180  			Name: "Success update of app template - no applications registered from the app template with changed name",
  1181  			Input: func() *model.ApplicationTemplateUpdateInput {
  1182  				return fixModelAppTemplateUpdateInput(updatedAppTemplateTestName, appInputJSONWithNewAppType)
  1183  			},
  1184  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1185  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1186  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1187  				appTemplateRepo.On("ListByName", ctx, updatedAppTemplateTestName).Return([]*model.ApplicationTemplate{}, nil).Once()
  1188  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithNewName).Return(nil).Once()
  1189  				return appTemplateRepo
  1190  			},
  1191  			WebhookRepoFn: func() *automock.WebhookRepository {
  1192  				webhookRepo := &automock.WebhookRepository{}
  1193  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1194  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1195  				return webhookRepo
  1196  			},
  1197  			LabelRepoFn: func() *automock.LabelRepository {
  1198  				labelRepo := &automock.LabelRepository{}
  1199  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1200  				return labelRepo
  1201  			},
  1202  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1203  				labelUpsertService := &automock.LabelUpsertService{}
  1204  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, mock.Anything).Return(nil).Once()
  1205  				return labelUpsertService
  1206  			},
  1207  			AppRepoFn: func() *automock.ApplicationRepository {
  1208  				appRepo := &automock.ApplicationRepository{}
  1209  				appRepo.On("ListAllByApplicationTemplateID", ctx, testID).Return([]*model.Application{}, nil).Once()
  1210  				return appRepo
  1211  			},
  1212  		},
  1213  		{
  1214  			Name: "Error while listing applications from this app template when app template name is changed",
  1215  			Input: func() *model.ApplicationTemplateUpdateInput {
  1216  				return fixModelAppTemplateUpdateInput(updatedAppTemplateTestName, appInputJSONWithNewAppType)
  1217  			},
  1218  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1219  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1220  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1221  				appTemplateRepo.On("ListByName", ctx, updatedAppTemplateTestName).Return([]*model.ApplicationTemplate{}, nil).Once()
  1222  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithNewName).Return(nil).Once()
  1223  				return appTemplateRepo
  1224  			},
  1225  			WebhookRepoFn: func() *automock.WebhookRepository {
  1226  				webhookRepo := &automock.WebhookRepository{}
  1227  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1228  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1229  				return webhookRepo
  1230  			},
  1231  			LabelRepoFn: func() *automock.LabelRepository {
  1232  				labelRepo := &automock.LabelRepository{}
  1233  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1234  				return labelRepo
  1235  			},
  1236  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1237  				labelUpsertService := &automock.LabelUpsertService{}
  1238  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, mock.Anything).Return(nil).Once()
  1239  				return labelUpsertService
  1240  			},
  1241  			AppRepoFn: func() *automock.ApplicationRepository {
  1242  				appRepo := &automock.ApplicationRepository{}
  1243  				appRepo.On("ListAllByApplicationTemplateID", ctx, testID).Return(nil, testError).Once()
  1244  				return appRepo
  1245  			},
  1246  			ExpectedError: testError,
  1247  		},
  1248  		{
  1249  			Name: "Success update of app template with changed name and the applicationType labels of applications registered from the app template",
  1250  			Input: func() *model.ApplicationTemplateUpdateInput {
  1251  				return fixModelAppTemplateUpdateInput(updatedAppTemplateTestName, appInputJSONWithNewAppType)
  1252  			},
  1253  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1254  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1255  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1256  				appTemplateRepo.On("ListByName", ctx, updatedAppTemplateTestName).Return([]*model.ApplicationTemplate{}, nil).Once()
  1257  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithNewName).Return(nil).Once()
  1258  				return appTemplateRepo
  1259  			},
  1260  			WebhookRepoFn: func() *automock.WebhookRepository {
  1261  				webhookRepo := &automock.WebhookRepository{}
  1262  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1263  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1264  				return webhookRepo
  1265  			},
  1266  			LabelRepoFn: func() *automock.LabelRepository {
  1267  				labelRepo := &automock.LabelRepository{}
  1268  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1269  				return labelRepo
  1270  			},
  1271  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1272  				labelUpsertSvc := &automock.LabelUpsertService{}
  1273  				labelUpsertSvc.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, mock.Anything).Return(nil).Once()
  1274  				labelUpsertSvc.On("UpsertLabelGlobal", ctx, modelLabelInput).Return(nil).Once()
  1275  				return labelUpsertSvc
  1276  			},
  1277  			AppRepoFn: func() *automock.ApplicationRepository {
  1278  				appRepo := &automock.ApplicationRepository{}
  1279  				appRepo.On("ListAllByApplicationTemplateID", ctx, testID).Return([]*model.Application{&modelApplicationFromTemplate}, nil).Once()
  1280  				return appRepo
  1281  			},
  1282  		},
  1283  		{
  1284  			Name: "Error while updating applicationType label of applications registered from the app template with changed name",
  1285  			Input: func() *model.ApplicationTemplateUpdateInput {
  1286  				return fixModelAppTemplateUpdateInput(updatedAppTemplateTestName, appInputJSONWithNewAppType)
  1287  			},
  1288  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1289  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1290  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1291  				appTemplateRepo.On("ListByName", ctx, updatedAppTemplateTestName).Return([]*model.ApplicationTemplate{}, nil).Once()
  1292  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithNewName).Return(nil).Once()
  1293  				return appTemplateRepo
  1294  			},
  1295  			WebhookRepoFn: func() *automock.WebhookRepository {
  1296  				webhookRepo := &automock.WebhookRepository{}
  1297  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1298  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1299  				return webhookRepo
  1300  			},
  1301  			LabelRepoFn: func() *automock.LabelRepository {
  1302  				labelRepo := &automock.LabelRepository{}
  1303  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1304  				return labelRepo
  1305  			},
  1306  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1307  				labelUpsertSvc := &automock.LabelUpsertService{}
  1308  				labelUpsertSvc.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, mock.Anything).Return(nil).Once()
  1309  				labelUpsertSvc.On("UpsertLabelGlobal", ctx, modelLabelInput).Return(testError).Once()
  1310  				return labelUpsertSvc
  1311  			},
  1312  			AppRepoFn: func() *automock.ApplicationRepository {
  1313  				appRepo := &automock.ApplicationRepository{}
  1314  				appRepo.On("ListAllByApplicationTemplateID", ctx, testID).Return([]*model.Application{&modelApplicationFromTemplate}, nil).Once()
  1315  				return appRepo
  1316  			},
  1317  			ExpectedError: testError,
  1318  		},
  1319  		{
  1320  			Name: "Error when getting application template",
  1321  			Input: func() *model.ApplicationTemplateUpdateInput {
  1322  				return fixModelAppTemplateUpdateInput(testName, appInputJSON)
  1323  			},
  1324  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1325  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1326  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(nil, testError).Once()
  1327  				return appTemplateRepo
  1328  			},
  1329  			WebhookRepoFn:    UnusedWebhookRepo,
  1330  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1331  			LabelRepoFn:      UnusedLabelRepo,
  1332  			AppRepoFn:        UnusedAppRepo,
  1333  			ExpectedError:    testError,
  1334  		},
  1335  		{
  1336  			Name: "Error when func enriching app input json with applicationType label - labels are not map[string]interface{}",
  1337  			Input: func() *model.ApplicationTemplateUpdateInput {
  1338  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":123,"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
  1339  				return fixModelAppTemplateUpdateInput(testName, appInputJSON)
  1340  			},
  1341  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1342  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1343  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1344  				return appTemplateRepo
  1345  			},
  1346  			WebhookRepoFn:    UnusedWebhookRepo,
  1347  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1348  			LabelRepoFn: func() *automock.LabelRepository {
  1349  				labelRepo := &automock.LabelRepository{}
  1350  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(&model.Label{Value: "eu-1"}, nil).Once()
  1351  				return labelRepo
  1352  			},
  1353  			AppRepoFn:     UnusedAppRepo,
  1354  			ExpectedError: errors.New("app input json labels are type map[string]interface {} instead of map[string]interface{}"),
  1355  		},
  1356  		{
  1357  			Name: "Error when func enriching app input json with applicationType label - application type is not string",
  1358  			Input: func() *model.ApplicationTemplateUpdateInput {
  1359  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":{"applicationType":123,"test":["val","val2"]},"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
  1360  				return fixModelAppTemplateUpdateInput(testName, appInputJSON)
  1361  			},
  1362  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1363  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1364  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1365  				return appTemplateRepo
  1366  			},
  1367  			WebhookRepoFn:    UnusedWebhookRepo,
  1368  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1369  			LabelRepoFn: func() *automock.LabelRepository {
  1370  				labelRepo := &automock.LabelRepository{}
  1371  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(&model.Label{Value: "eu-1"}, nil).Once()
  1372  				return labelRepo
  1373  			},
  1374  			AppRepoFn:     UnusedAppRepo,
  1375  			ExpectedError: errors.New("\"applicationType\" label value must be string"),
  1376  		},
  1377  		{
  1378  			Name: "Error when func enriching app input json with applicationType label - application type value does not match the application template name",
  1379  			Input: func() *model.ApplicationTemplateUpdateInput {
  1380  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":{"applicationType":"random-text","test":["val","val2"]},"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
  1381  				return fixModelAppTemplateUpdateInput(testName, appInputJSON)
  1382  			},
  1383  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1384  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1385  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1386  				return appTemplateRepo
  1387  			},
  1388  			WebhookRepoFn:    UnusedWebhookRepo,
  1389  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1390  			LabelRepoFn: func() *automock.LabelRepository {
  1391  				labelRepo := &automock.LabelRepository{}
  1392  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(&model.Label{Value: "eu-1"}, nil).Once()
  1393  				return labelRepo
  1394  			},
  1395  			AppRepoFn:     UnusedAppRepo,
  1396  			ExpectedError: errors.New("\"applicationType\" label value does not match the application template name"),
  1397  		},
  1398  		{
  1399  			Name: "No error in func enriching app input json with applicationType label when application type value does not match the application template name for Other System Type",
  1400  			Input: func() *model.ApplicationTemplateUpdateInput {
  1401  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":{"applicationType":"random-text","test":["val","val2"]},"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
  1402  				return fixModelAppTemplateUpdateInputWithLabels(testNameOtherSystemType, appInputJSON, newTestLabels)
  1403  			},
  1404  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1405  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1406  				appInputJSON := `{"name":"foo","providerName":"compass","description":"Lorem ipsum","labels":{"applicationType":"random-text","test":["val","val2"]},"healthCheckURL":"https://foo.bar","webhooks":[{"type":"","url":"webhook1.foo.bar","auth":null},{"type":"","url":"webhook2.foo.bar","auth":null}],"integrationSystemID":"iiiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii"}`
  1407  
  1408  				modelOtherSystemTypeUpdate := fixModelAppTemplateWithAppInputJSONAndLabels(testID, testNameOtherSystemType, appInputJSON, []*model.Webhook{}, newTestLabels)
  1409  				appTemplateRepo.On("Get", ctx, modelAppTemplateOtherSystemType.ID).Return(modelAppTemplateOtherSystemType, nil).Once()
  1410  				appTemplateRepo.On("Update", ctx, *modelOtherSystemTypeUpdate).Return(nil).Once()
  1411  				return appTemplateRepo
  1412  			},
  1413  			WebhookRepoFn: func() *automock.WebhookRepository {
  1414  				webhookRepo := &automock.WebhookRepository{}
  1415  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1416  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1417  				return webhookRepo
  1418  			},
  1419  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1420  				labelUpsertService := &automock.LabelUpsertService{}
  1421  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, mock.Anything).Return(nil).Once()
  1422  				return labelUpsertService
  1423  			},
  1424  			LabelRepoFn: func() *automock.LabelRepository {
  1425  				labelRepo := &automock.LabelRepository{}
  1426  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(&model.Label{Value: "eu-1"}, nil).Once()
  1427  
  1428  				return labelRepo
  1429  			},
  1430  			AppRepoFn:     UnusedAppRepo,
  1431  			ExpectedError: nil,
  1432  		},
  1433  		{
  1434  			Name: "Error when updating application template - retrieve region failed",
  1435  			Input: func() *model.ApplicationTemplateUpdateInput {
  1436  				return fixModelAppTemplateUpdateInput(testName+"test", appInputJSON)
  1437  			},
  1438  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1439  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1440  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1441  				return appTemplateRepo
  1442  			},
  1443  			WebhookRepoFn:    UnusedWebhookRepo,
  1444  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1445  			LabelRepoFn: func() *automock.LabelRepository {
  1446  				labelRepo := &automock.LabelRepository{}
  1447  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, testError).Once()
  1448  				return labelRepo
  1449  			},
  1450  			AppRepoFn:     UnusedAppRepo,
  1451  			ExpectedError: testError,
  1452  		},
  1453  		{
  1454  			Name: "Error when updating application template - exists check failed",
  1455  			Input: func() *model.ApplicationTemplateUpdateInput {
  1456  				return fixModelAppTemplateUpdateInput(testName+"test", appInputJSONString)
  1457  			},
  1458  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1459  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1460  				appTemplateRepo.On("ListByName", ctx, testName+"test").Return([]*model.ApplicationTemplate{modelAppTemplate}, nil).Once()
  1461  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1462  				return appTemplateRepo
  1463  			},
  1464  			WebhookRepoFn:    UnusedWebhookRepo,
  1465  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1466  			LabelRepoFn: func() *automock.LabelRepository {
  1467  				labelRepo := &automock.LabelRepository{}
  1468  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1469  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, testError).Once()
  1470  				return labelRepo
  1471  			},
  1472  			AppRepoFn:     UnusedAppRepo,
  1473  			ExpectedError: testError,
  1474  		},
  1475  		{
  1476  			Name: "Error when application template already exists",
  1477  			Input: func() *model.ApplicationTemplateUpdateInput {
  1478  				return fixModelAppTemplateUpdateInput(testName+"test", appInputJSONString)
  1479  			},
  1480  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1481  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1482  				appTemplateRepo.On("ListByName", ctx, testName+"test").Return([]*model.ApplicationTemplate{modelAppTemplate}, nil).Once()
  1483  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1484  				return appTemplateRepo
  1485  			},
  1486  			WebhookRepoFn:    UnusedWebhookRepo,
  1487  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1488  			LabelRepoFn: func() *automock.LabelRepository {
  1489  				labelRepo := &automock.LabelRepository{}
  1490  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1491  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1492  				return labelRepo
  1493  			},
  1494  			AppRepoFn:     UnusedAppRepo,
  1495  			ExpectedError: errors.New("application template with name \"bartest\" and region <nil> already exists"),
  1496  		},
  1497  		{
  1498  			Name: "Error when updating application template - update failed",
  1499  			Input: func() *model.ApplicationTemplateUpdateInput {
  1500  				return fixModelAppTemplateUpdateInputWithLabels(testName, appInputJSON, newTestLabels)
  1501  			},
  1502  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1503  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1504  				appTemplateRepo.On("Get", ctx, modelAppTemplate.ID).Return(modelAppTemplate, nil).Once()
  1505  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithLabels).Return(testError).Once()
  1506  				return appTemplateRepo
  1507  			},
  1508  			WebhookRepoFn:    UnusedWebhookRepo,
  1509  			LabelUpsertSvcFn: UnusedLabelUpsertSvc,
  1510  			LabelRepoFn: func() *automock.LabelRepository {
  1511  				labelRepo := &automock.LabelRepository{}
  1512  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1513  				return labelRepo
  1514  			},
  1515  			AppRepoFn:     UnusedAppRepo,
  1516  			ExpectedError: testError,
  1517  		},
  1518  		{
  1519  			Name: "Error when updating labels of application template - upsert failed",
  1520  			Input: func() *model.ApplicationTemplateUpdateInput {
  1521  				return modelAppTemplateUpdateInput
  1522  			},
  1523  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1524  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1525  				appTemplateRepo.On("Get", ctx, modelAppTemplateWithLabels.ID).Return(modelAppTemplateWithLabels, nil).Once()
  1526  				appTemplateRepo.On("Update", ctx, *modelAppTemplateWithLabels).Return(nil).Once()
  1527  				return appTemplateRepo
  1528  			},
  1529  			WebhookRepoFn: func() *automock.WebhookRepository {
  1530  				webhookRepo := &automock.WebhookRepository{}
  1531  				webhookRepo.On("DeleteAllByApplicationTemplateID", ctx, modelAppTemplateWithLabels.ID).Return(nil).Once()
  1532  				webhookRepo.On("CreateMany", ctx, "", []*model.Webhook{}).Return(nil).Once()
  1533  				return webhookRepo
  1534  			},
  1535  			LabelUpsertSvcFn: func() *automock.LabelUpsertService {
  1536  				labelUpsertService := &automock.LabelUpsertService{}
  1537  				labelUpsertService.On("UpsertMultipleLabels", ctx, "", model.AppTemplateLabelableObject, testID, modelAppTemplateUpdateInput.Labels).Return(testError).Once()
  1538  				return labelUpsertService
  1539  			},
  1540  			LabelRepoFn: func() *automock.LabelRepository {
  1541  				labelRepo := &automock.LabelRepository{}
  1542  				labelRepo.On("GetByKey", ctx, "", model.AppTemplateLabelableObject, modelAppTemplate.ID, "region").Return(nil, apperrors.NewNotFoundError(resource.Label, "id")).Once()
  1543  				return labelRepo
  1544  			},
  1545  			AppRepoFn:     UnusedAppRepo,
  1546  			ExpectedError: testError,
  1547  		},
  1548  	}
  1549  
  1550  	for _, testCase := range testCases {
  1551  		t.Run(testCase.Name, func(t *testing.T) {
  1552  			appTemplateRepo := testCase.AppTemplateRepoFn()
  1553  			webhookRepo := testCase.WebhookRepoFn()
  1554  			labelRepo := testCase.LabelRepoFn()
  1555  			labelUpsertService := testCase.LabelUpsertSvcFn()
  1556  			appRepo := testCase.AppRepoFn()
  1557  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, nil, labelUpsertService, labelRepo, appRepo)
  1558  
  1559  			// WHEN
  1560  			err := svc.Update(ctx, testID, *testCase.Input())
  1561  
  1562  			// THEN
  1563  			if testCase.ExpectedError != nil {
  1564  				require.Error(t, err)
  1565  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1566  			} else {
  1567  				assert.NoError(t, err)
  1568  			}
  1569  
  1570  			appTemplateRepo.AssertExpectations(t)
  1571  			labelRepo.AssertExpectations(t)
  1572  			labelUpsertService.AssertExpectations(t)
  1573  			appRepo.AssertExpectations(t)
  1574  		})
  1575  	}
  1576  }
  1577  
  1578  func TestService_Delete(t *testing.T) {
  1579  	// GIVEN
  1580  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
  1581  
  1582  	testCases := []struct {
  1583  		Name              string
  1584  		AppTemplateRepoFn func() *automock.ApplicationTemplateRepository
  1585  		WebhookRepoFn     func() *automock.WebhookRepository
  1586  		ExpectedError     error
  1587  	}{
  1588  		{
  1589  			Name: "Success",
  1590  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1591  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1592  				appTemplateRepo.On("Delete", ctx, testID).Return(nil).Once()
  1593  				return appTemplateRepo
  1594  			},
  1595  			WebhookRepoFn: UnusedWebhookRepo,
  1596  		},
  1597  		{
  1598  			Name: "Error when deleting application template",
  1599  			AppTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
  1600  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
  1601  				appTemplateRepo.On("Delete", ctx, testID).Return(testError).Once()
  1602  				return appTemplateRepo
  1603  			},
  1604  			WebhookRepoFn: UnusedWebhookRepo,
  1605  			ExpectedError: testError,
  1606  		},
  1607  	}
  1608  
  1609  	for _, testCase := range testCases {
  1610  		t.Run(testCase.Name, func(t *testing.T) {
  1611  			appTemplateRepo := testCase.AppTemplateRepoFn()
  1612  			webhookRepo := testCase.WebhookRepoFn()
  1613  			svc := apptemplate.NewService(appTemplateRepo, webhookRepo, nil, nil, nil, nil)
  1614  
  1615  			// WHEN
  1616  			err := svc.Delete(ctx, testID)
  1617  
  1618  			// THEN
  1619  			if testCase.ExpectedError != nil {
  1620  				require.Error(t, err)
  1621  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1622  			} else {
  1623  				assert.NoError(t, err)
  1624  			}
  1625  
  1626  			appTemplateRepo.AssertExpectations(t)
  1627  		})
  1628  	}
  1629  }
  1630  
  1631  func TestService_PrepareApplicationCreateInputJSON(t *testing.T) {
  1632  	// GIVEN
  1633  	svc := apptemplate.NewService(nil, nil, nil, nil, nil, nil)
  1634  	placeholderNotOptional := false
  1635  	placeholderIsOptional := true
  1636  
  1637  	testCases := []struct {
  1638  		Name             string
  1639  		InputAppTemplate *model.ApplicationTemplate
  1640  		InputValues      model.ApplicationFromTemplateInputValues
  1641  		ExpectedOutput   string
  1642  		ExpectedError    error
  1643  	}{
  1644  		{
  1645  			Name: "Success when no placeholders",
  1646  			InputAppTemplate: &model.ApplicationTemplate{
  1647  				ApplicationInputJSON: `{"Name": "my-app", "Description": "Lorem ipsum"}`,
  1648  				Placeholders:         nil,
  1649  			},
  1650  			InputValues:    nil,
  1651  			ExpectedOutput: `{"Name": "my-app", "Description": "Lorem ipsum"}`,
  1652  			ExpectedError:  nil,
  1653  		},
  1654  		{
  1655  			Name: "Success when with placeholders",
  1656  			InputAppTemplate: &model.ApplicationTemplate{
  1657  				ApplicationInputJSON: `{"Name": "{{name}}", "Description": "Lorem ipsum"}`,
  1658  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1659  					{Name: "name", Description: str.Ptr("Application name"), JSONPath: str.Ptr("displayName"), Optional: &placeholderNotOptional},
  1660  				},
  1661  			},
  1662  			InputValues: []*model.ApplicationTemplateValueInput{
  1663  				{Placeholder: "name", Value: "my-application"},
  1664  			},
  1665  			ExpectedOutput: `{"Name": "my-application", "Description": "Lorem ipsum"}`,
  1666  			ExpectedError:  nil,
  1667  		},
  1668  		{
  1669  			Name: "Success when optional placeholder is not provided on root level",
  1670  			InputAppTemplate: &model.ApplicationTemplate{
  1671  				ApplicationInputJSON: `{"Name": "{{Name}}", "Description": "Lorem ipsum"}`,
  1672  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1673  					{Name: "Name", Description: str.Ptr("Application name"), JSONPath: str.Ptr("displayName"), Optional: &placeholderIsOptional},
  1674  				},
  1675  			},
  1676  			InputValues:    []*model.ApplicationTemplateValueInput{},
  1677  			ExpectedOutput: `{"Name":"","Description":"Lorem ipsum"}`,
  1678  			ExpectedError:  nil,
  1679  		},
  1680  		{
  1681  			Name: "Success when optional placeholder is not provided in labels",
  1682  			InputAppTemplate: &model.ApplicationTemplate{
  1683  				ApplicationInputJSON: `{"Name": "{{Name}}", "labels": {"label1":"label1" ,"optionalLabel": "{{optionalLabel}}"}, "Description": "Lorem ipsum"}`,
  1684  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1685  					{Name: "Name", Description: str.Ptr("Application name"), JSONPath: str.Ptr("displayName"), Optional: &placeholderIsOptional},
  1686  					{Name: "optionalLabel", Description: str.Ptr("optionalLabel description"), JSONPath: str.Ptr("optionalLabel"), Optional: &placeholderIsOptional},
  1687  				},
  1688  			},
  1689  			InputValues:    []*model.ApplicationTemplateValueInput{},
  1690  			ExpectedOutput: `{"Name":"","Description":"Lorem ipsum", "labels":{"label1":"label1"}}`,
  1691  			ExpectedError:  nil,
  1692  		},
  1693  		{
  1694  			Name: "Success when optional placeholder value in labels is empty string",
  1695  			InputAppTemplate: &model.ApplicationTemplate{
  1696  				ApplicationInputJSON: `{"labels": {"label1":"label1" ,"nonOptionalLabel": "{{nonOptionalLabel}}"}, "Description": "Lorem ipsum"}`,
  1697  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1698  					{Name: "nonOptionalLabel", Description: str.Ptr("nonOptionalLabel description"), JSONPath: str.Ptr("nonOptionalLabel"), Optional: &placeholderNotOptional},
  1699  				},
  1700  			},
  1701  			InputValues: []*model.ApplicationTemplateValueInput{
  1702  				{Placeholder: "nonOptionalLabel", Value: ""},
  1703  			},
  1704  			ExpectedOutput: `{"Description":"Lorem ipsum","labels":{"label1":"label1"}}`,
  1705  			ExpectedError:  nil,
  1706  		},
  1707  		{
  1708  			Name: "Returns error when app input is invalid JSON",
  1709  			InputAppTemplate: &model.ApplicationTemplate{
  1710  				ApplicationInputJSON: `{{}`,
  1711  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1712  					{Name: "nonOptionalLabel", Description: str.Ptr("nonOptionalLabel description"), JSONPath: str.Ptr("nonOptionalLabel"), Optional: &placeholderNotOptional},
  1713  				},
  1714  			},
  1715  			InputValues: []*model.ApplicationTemplateValueInput{
  1716  				{Placeholder: "nonOptionalLabel", Value: ""},
  1717  			},
  1718  			ExpectedOutput: "",
  1719  			ExpectedError:  errors.New("error while clear optional empty value"),
  1720  		},
  1721  		{
  1722  			Name: "Returns error when required placeholder value not provided in labels",
  1723  			InputAppTemplate: &model.ApplicationTemplate{
  1724  				ApplicationInputJSON: `{"labels": {"label1":"label1" ,"nonOptionalLabel": "{{nonOptionalLabel}}"}, "Description": "Lorem ipsum"}`,
  1725  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1726  					{Name: "nonOptionalLabel", Description: str.Ptr("nonOptionalLabel description"), JSONPath: str.Ptr("nonOptionalLabel"), Optional: &placeholderNotOptional},
  1727  				},
  1728  			},
  1729  			InputValues:    []*model.ApplicationTemplateValueInput{},
  1730  			ExpectedOutput: "",
  1731  			ExpectedError:  errors.New("required placeholder not provided: value for placeholder name 'nonOptionalLabel' not found"),
  1732  		},
  1733  		{
  1734  			Name: "Returns error when required placeholder value not provided on root level",
  1735  			InputAppTemplate: &model.ApplicationTemplate{
  1736  				ApplicationInputJSON: `{"Name": "{{name}}", "Description": "Lorem ipsum"}`,
  1737  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1738  					{Name: "name", Description: str.Ptr("Application name"), JSONPath: str.Ptr("displayName"), Optional: &placeholderNotOptional},
  1739  				},
  1740  			},
  1741  			InputValues:    []*model.ApplicationTemplateValueInput{},
  1742  			ExpectedOutput: "",
  1743  			ExpectedError:  errors.New("required placeholder not provided: value for placeholder name 'name' not found"),
  1744  		},
  1745  		{
  1746  			Name: "Returns error when provider placeholder value contains \"SAP\"",
  1747  			InputAppTemplate: &model.ApplicationTemplate{
  1748  				ApplicationInputJSON: `{"Provider": "{{provider}}", "Description": "Lorem ipsum"}`,
  1749  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1750  					{Name: "provider", Description: str.Ptr("Application's provider"), JSONPath: str.Ptr("provider"), Optional: &placeholderNotOptional},
  1751  				},
  1752  			},
  1753  			InputValues: []*model.ApplicationTemplateValueInput{
  1754  				{Placeholder: "provider", Value: "invalid SAP provider"},
  1755  			},
  1756  			ExpectedOutput: "",
  1757  			ExpectedError:  errors.New("value of placeholder is invalid: provider cannot contain \"SAP\""),
  1758  		},
  1759  		{
  1760  			Name: "Returns error when application type placeholder value starts with \"SAP\"",
  1761  			InputAppTemplate: &model.ApplicationTemplate{
  1762  				ApplicationInputJSON: `{"Application type": "{{application-type}}", "Description": "Lorem ipsum"}`,
  1763  				Placeholders: []model.ApplicationTemplatePlaceholder{
  1764  					{Name: "application-type", Description: str.Ptr("Application type"), JSONPath: str.Ptr("application-type"), Optional: &placeholderNotOptional},
  1765  				},
  1766  			},
  1767  			InputValues: []*model.ApplicationTemplateValueInput{
  1768  				{Placeholder: "application-type", Value: "SAP type"},
  1769  			},
  1770  			ExpectedOutput: "",
  1771  			ExpectedError:  errors.New("value of placeholder is invalid: your application type cannot start with \"SAP\""),
  1772  		},
  1773  	}
  1774  
  1775  	for _, testCase := range testCases {
  1776  		t.Run(testCase.Name, func(t *testing.T) {
  1777  			// WHEN
  1778  			result, err := svc.PrepareApplicationCreateInputJSON(testCase.InputAppTemplate, testCase.InputValues)
  1779  
  1780  			// THEN
  1781  			if testCase.ExpectedError != nil {
  1782  				require.Error(t, err)
  1783  				assert.Empty(t, result)
  1784  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1785  			} else {
  1786  				require.NoError(t, err)
  1787  				assert.JSONEq(t, testCase.ExpectedOutput, result)
  1788  			}
  1789  		})
  1790  	}
  1791  }
  1792  
  1793  func UnusedLabelRepo() *automock.LabelRepository {
  1794  	return &automock.LabelRepository{}
  1795  }
  1796  
  1797  func UnusedWebhookRepo() *automock.WebhookRepository {
  1798  	return &automock.WebhookRepository{}
  1799  }
  1800  
  1801  func UnusedLabelUpsertSvc() *automock.LabelUpsertService {
  1802  	return &automock.LabelUpsertService{}
  1803  }
  1804  
  1805  func UnusedAppTemplateRepo() *automock.ApplicationTemplateRepository {
  1806  	return &automock.ApplicationTemplateRepository{}
  1807  }
  1808  
  1809  func UnusedAppRepo() *automock.ApplicationRepository {
  1810  	return &automock.ApplicationRepository{}
  1811  }