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

     1  package runtimectx_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
     9  
    10  	runtimectx "github.com/kyma-incubator/compass/components/director/internal/domain/runtime_context"
    11  	"github.com/kyma-incubator/compass/components/director/internal/labelfilter"
    12  	"github.com/kyma-incubator/compass/components/director/pkg/pagination"
    13  
    14  	"github.com/kyma-incubator/compass/components/director/internal/domain/runtime_context/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/pkg/errors"
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/mock"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestService_Exist(t *testing.T) {
    24  	tnt := "tenant"
    25  	externalTnt := "external-tnt"
    26  	ctx := context.TODO()
    27  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
    28  	testError := errors.New("Test error")
    29  
    30  	rtmCtxID := "id"
    31  
    32  	testCases := []struct {
    33  		Name                  string
    34  		RepositoryFn          func() *automock.RuntimeContextRepository
    35  		InputRuntimeContextID string
    36  		ExpectedValue         bool
    37  		ExpectedError         error
    38  	}{
    39  		{
    40  			Name: "RuntimeContext exists",
    41  			RepositoryFn: func() *automock.RuntimeContextRepository {
    42  				repo := &automock.RuntimeContextRepository{}
    43  				repo.On("Exists", ctx, tnt, rtmCtxID).Return(true, nil)
    44  				return repo
    45  			},
    46  			InputRuntimeContextID: rtmCtxID,
    47  			ExpectedValue:         true,
    48  			ExpectedError:         nil,
    49  		},
    50  		{
    51  			Name: "RuntimeContext not exits",
    52  			RepositoryFn: func() *automock.RuntimeContextRepository {
    53  				repo := &automock.RuntimeContextRepository{}
    54  				repo.On("Exists", ctx, tnt, rtmCtxID).Return(false, nil)
    55  				return repo
    56  			},
    57  			InputRuntimeContextID: rtmCtxID,
    58  			ExpectedValue:         false,
    59  			ExpectedError:         nil,
    60  		},
    61  		{
    62  			Name: "Returns error",
    63  			RepositoryFn: func() *automock.RuntimeContextRepository {
    64  				repo := &automock.RuntimeContextRepository{}
    65  				repo.On("Exists", ctx, tnt, rtmCtxID).Return(false, testError)
    66  				return repo
    67  			},
    68  			InputRuntimeContextID: rtmCtxID,
    69  			ExpectedValue:         false,
    70  			ExpectedError:         testError,
    71  		},
    72  	}
    73  
    74  	for _, testCase := range testCases {
    75  		t.Run(testCase.Name, func(t *testing.T) {
    76  			// GIVEN
    77  			rtmCtxRepo := testCase.RepositoryFn()
    78  			svc := runtimectx.NewService(rtmCtxRepo, nil, nil, nil, nil, nil, nil)
    79  
    80  			// WHEN
    81  			value, err := svc.Exist(ctx, testCase.InputRuntimeContextID)
    82  
    83  			// THEN
    84  			if testCase.ExpectedError != nil {
    85  				require.Error(t, err)
    86  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
    87  			} else {
    88  				require.Nil(t, err)
    89  			}
    90  
    91  			assert.Equal(t, testCase.ExpectedValue, value)
    92  			rtmCtxRepo.AssertExpectations(t)
    93  		})
    94  	}
    95  	t.Run("Returns error on loading tenant", func(t *testing.T) {
    96  		// GIVEN
    97  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
    98  		// WHEN
    99  		_, err := svc.Exist(context.TODO(), "id")
   100  		// THEN
   101  		require.Error(t, err)
   102  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
   103  	})
   104  }
   105  
   106  func TestService_Create(t *testing.T) {
   107  	// GIVEN
   108  	testErr := errors.New("Test error")
   109  	scenario := "scenario"
   110  	id := "foo"
   111  	runtimeID := "runtime_id"
   112  	key := "key"
   113  	val := "val"
   114  	modelInput := model.RuntimeContextInput{
   115  		Key:       key,
   116  		Value:     val,
   117  		RuntimeID: runtimeID,
   118  	}
   119  
   120  	runtimeCtxModel := mock.MatchedBy(func(rtmCtx *model.RuntimeContext) bool {
   121  		return rtmCtx.Key == modelInput.Key && rtmCtx.Value == modelInput.Value && rtmCtx.RuntimeID == modelInput.RuntimeID
   122  	})
   123  
   124  	tnt := "tenant"
   125  	externalTnt := "external-tnt"
   126  	parentTnt := "parent"
   127  	modelTnt := &model.BusinessTenantMapping{ID: tnt, Parent: parentTnt}
   128  	ctxWithoutTenant := context.TODO()
   129  	ctxWithTenant := tenant.SaveToContext(ctxWithoutTenant, tnt, externalTnt)
   130  	ctxWithParentTenant := tenant.SaveToContext(ctxWithTenant, parentTnt, "")
   131  	formations := []string{"scenario"}
   132  
   133  	testCases := []struct {
   134  		Name                       string
   135  		RuntimeContextRepositoryFn func() *automock.RuntimeContextRepository
   136  		UIDServiceFn               func() *automock.UIDService
   137  		TenantServiceFN            func() *automock.TenantService
   138  		FormationServiceFn         func() *automock.FormationService
   139  		RuntimeRepositoryFn        func() *automock.RuntimeRepository
   140  		Input                      model.RuntimeContextInput
   141  		Context                    context.Context
   142  		ExpectedErrMessage         string
   143  	}{
   144  		{
   145  			Name: "Success when runtime context's runtime have owner=false",
   146  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   147  				repo := &automock.RuntimeContextRepository{}
   148  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   149  				return repo
   150  			},
   151  			UIDServiceFn: func() *automock.UIDService {
   152  				svc := &automock.UIDService{}
   153  				svc.On("Generate").Return(id)
   154  				return svc
   155  			},
   156  			FormationServiceFn: func() *automock.FormationService {
   157  				formationSvc := &automock.FormationService{}
   158  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once()
   159  				formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once()
   160  				return formationSvc
   161  			},
   162  			RuntimeRepositoryFn: func() *automock.RuntimeRepository {
   163  				repo := &automock.RuntimeRepository{}
   164  				repo.On("OwnerExists", ctxWithTenant, tnt, runtimeID).Return(false, nil).Once()
   165  				return repo
   166  			},
   167  			TenantServiceFN: func() *automock.TenantService {
   168  				tenantSvc := &automock.TenantService{}
   169  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   170  				return tenantSvc
   171  			},
   172  			Input:              modelInput,
   173  			Context:            ctxWithTenant,
   174  			ExpectedErrMessage: "",
   175  		},
   176  		{
   177  			Name: "Success when runtime context's runtime have owner=true",
   178  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   179  				repo := &automock.RuntimeContextRepository{}
   180  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   181  				return repo
   182  			},
   183  			UIDServiceFn: func() *automock.UIDService {
   184  				svc := &automock.UIDService{}
   185  				svc.On("Generate").Return(id)
   186  				return svc
   187  			},
   188  			FormationServiceFn: func() *automock.FormationService {
   189  				formationSvc := &automock.FormationService{}
   190  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once()
   191  				formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once()
   192  				formationSvc.On("UnassignFormation", ctxWithParentTenant, parentTnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: scenario}).Return(nil, nil).Once()
   193  				return formationSvc
   194  			},
   195  			RuntimeRepositoryFn: func() *automock.RuntimeRepository {
   196  				repo := &automock.RuntimeRepository{}
   197  				repo.On("OwnerExists", ctxWithTenant, tnt, runtimeID).Return(true, nil).Once()
   198  				return repo
   199  			},
   200  			TenantServiceFN: func() *automock.TenantService {
   201  				tenantSvc := &automock.TenantService{}
   202  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   203  				return tenantSvc
   204  			},
   205  			Input:              modelInput,
   206  			Context:            ctxWithTenant,
   207  			ExpectedErrMessage: "",
   208  		},
   209  		{
   210  			Name: "Success when there aren't any scenarios from matching ASAs",
   211  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   212  				repo := &automock.RuntimeContextRepository{}
   213  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   214  				return repo
   215  			},
   216  			UIDServiceFn: func() *automock.UIDService {
   217  				svc := &automock.UIDService{}
   218  				svc.On("Generate").Return(id)
   219  				return svc
   220  			},
   221  			FormationServiceFn: func() *automock.FormationService {
   222  				formationSvc := &automock.FormationService{}
   223  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return([]string{}, nil).Once()
   224  				return formationSvc
   225  			},
   226  			RuntimeRepositoryFn: unusedRuntimeRepo,
   227  			TenantServiceFN: func() *automock.TenantService {
   228  				tenantSvc := &automock.TenantService{}
   229  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   230  				return tenantSvc
   231  			},
   232  			Input:              modelInput,
   233  			Context:            ctxWithTenant,
   234  			ExpectedErrMessage: "",
   235  		},
   236  		{
   237  			Name: "Returns error when checking if runtime with owner=true exists fails",
   238  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   239  				repo := &automock.RuntimeContextRepository{}
   240  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   241  				return repo
   242  			},
   243  			UIDServiceFn: func() *automock.UIDService {
   244  				svc := &automock.UIDService{}
   245  				svc.On("Generate").Return(id)
   246  				return svc
   247  			},
   248  			FormationServiceFn: func() *automock.FormationService {
   249  				formationSvc := &automock.FormationService{}
   250  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once()
   251  				return formationSvc
   252  			},
   253  			RuntimeRepositoryFn: func() *automock.RuntimeRepository {
   254  				repo := &automock.RuntimeRepository{}
   255  				repo.On("OwnerExists", ctxWithTenant, tnt, runtimeID).Return(false, testErr).Once()
   256  				return repo
   257  			},
   258  			TenantServiceFN: func() *automock.TenantService {
   259  				tenantSvc := &automock.TenantService{}
   260  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   261  				return tenantSvc
   262  			},
   263  			Input:              modelInput,
   264  			Context:            ctxWithTenant,
   265  			ExpectedErrMessage: testErr.Error(),
   266  		},
   267  		{
   268  			Name: "Returns error when unassign formation from runtime fails",
   269  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   270  				repo := &automock.RuntimeContextRepository{}
   271  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   272  				return repo
   273  			},
   274  			UIDServiceFn: func() *automock.UIDService {
   275  				svc := &automock.UIDService{}
   276  				svc.On("Generate").Return(id)
   277  				return svc
   278  			},
   279  			FormationServiceFn: func() *automock.FormationService {
   280  				formationSvc := &automock.FormationService{}
   281  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once()
   282  				formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once()
   283  				formationSvc.On("UnassignFormation", ctxWithParentTenant, parentTnt, runtimeID, graphql.FormationObjectTypeRuntime, model.Formation{Name: scenario}).Return(nil, testErr).Once()
   284  				return formationSvc
   285  			},
   286  			RuntimeRepositoryFn: func() *automock.RuntimeRepository {
   287  				repo := &automock.RuntimeRepository{}
   288  				repo.On("OwnerExists", ctxWithTenant, tnt, runtimeID).Return(true, nil).Once()
   289  				return repo
   290  			},
   291  			TenantServiceFN: func() *automock.TenantService {
   292  				tenantSvc := &automock.TenantService{}
   293  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   294  				return tenantSvc
   295  			},
   296  			Input:              modelInput,
   297  			Context:            ctxWithTenant,
   298  			ExpectedErrMessage: testErr.Error(),
   299  		},
   300  		{
   301  			Name: "Returns error when runtime context creation failed",
   302  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   303  				repo := &automock.RuntimeContextRepository{}
   304  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(testErr).Once()
   305  				return repo
   306  			},
   307  			UIDServiceFn: func() *automock.UIDService {
   308  				svc := &automock.UIDService{}
   309  				svc.On("Generate").Return("").Once()
   310  				return svc
   311  			},
   312  			FormationServiceFn:  unusedFormationService,
   313  			TenantServiceFN:     unusedTenantService,
   314  			RuntimeRepositoryFn: unusedRuntimeRepo,
   315  			Input:               modelInput,
   316  			Context:             ctxWithTenant,
   317  			ExpectedErrMessage:  testErr.Error(),
   318  		},
   319  		{
   320  			Name:                       "Returns error on loading tenant",
   321  			RuntimeContextRepositoryFn: unusedRuntimeContextRepo,
   322  			UIDServiceFn:               unusedUIDService,
   323  			FormationServiceFn:         unusedFormationService,
   324  			TenantServiceFN:            unusedTenantService,
   325  			RuntimeRepositoryFn:        unusedRuntimeRepo,
   326  			Input:                      model.RuntimeContextInput{},
   327  			Context:                    ctxWithoutTenant,
   328  			ExpectedErrMessage:         "while loading tenant from context: cannot read tenant from context",
   329  		},
   330  		{
   331  			Name: "Returns error when fetching tenant",
   332  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   333  				repo := &automock.RuntimeContextRepository{}
   334  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   335  				return repo
   336  			},
   337  			UIDServiceFn: func() *automock.UIDService {
   338  				svc := &automock.UIDService{}
   339  				svc.On("Generate").Return(id)
   340  				return svc
   341  			},
   342  			FormationServiceFn:  unusedFormationService,
   343  			RuntimeRepositoryFn: unusedRuntimeRepo,
   344  			TenantServiceFN: func() *automock.TenantService {
   345  				tenantSvc := &automock.TenantService{}
   346  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(nil, testErr).Once()
   347  				return tenantSvc
   348  			},
   349  			Input:              modelInput,
   350  			Context:            ctxWithTenant,
   351  			ExpectedErrMessage: "while getting tenant with id",
   352  		},
   353  		{
   354  			Name: "Returns error when getting ASAs from parent",
   355  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   356  				repo := &automock.RuntimeContextRepository{}
   357  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   358  				return repo
   359  			},
   360  			UIDServiceFn: func() *automock.UIDService {
   361  				svc := &automock.UIDService{}
   362  				svc.On("Generate").Return(id)
   363  				return svc
   364  			},
   365  			FormationServiceFn: func() *automock.FormationService {
   366  				formationSvc := &automock.FormationService{}
   367  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(nil, testErr).Once()
   368  				return formationSvc
   369  			},
   370  			RuntimeRepositoryFn: unusedRuntimeRepo,
   371  			TenantServiceFN: func() *automock.TenantService {
   372  				tenantSvc := &automock.TenantService{}
   373  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   374  				return tenantSvc
   375  			},
   376  			Input:              modelInput,
   377  			Context:            ctxWithTenant,
   378  			ExpectedErrMessage: "while getting formations from automatic scenario assignments",
   379  		},
   380  		{
   381  			Name: "Returns error while assigning runtime context to formation",
   382  			RuntimeContextRepositoryFn: func() *automock.RuntimeContextRepository {
   383  				repo := &automock.RuntimeContextRepository{}
   384  				repo.On("Create", ctxWithTenant, tnt, runtimeCtxModel).Return(nil).Once()
   385  				return repo
   386  			},
   387  			UIDServiceFn: func() *automock.UIDService {
   388  				svc := &automock.UIDService{}
   389  				svc.On("Generate").Return(id)
   390  				return svc
   391  			},
   392  			FormationServiceFn: func() *automock.FormationService {
   393  				formationSvc := &automock.FormationService{}
   394  				formationSvc.On("GetScenariosFromMatchingASAs", ctxWithParentTenant, id, graphql.FormationObjectTypeRuntimeContext).Return(formations, nil).Once()
   395  				formationSvc.On("AssignFormation", ctxWithParentTenant, parentTnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, testErr).Once()
   396  				return formationSvc
   397  			},
   398  			RuntimeRepositoryFn: func() *automock.RuntimeRepository {
   399  				repo := &automock.RuntimeRepository{}
   400  				repo.On("OwnerExists", ctxWithTenant, tnt, runtimeID).Return(false, nil).Once()
   401  				return repo
   402  			},
   403  			TenantServiceFN: func() *automock.TenantService {
   404  				tenantSvc := &automock.TenantService{}
   405  				tenantSvc.On("GetTenantByID", ctxWithTenant, tnt).Return(modelTnt, nil).Once()
   406  				return tenantSvc
   407  			},
   408  			Input:              modelInput,
   409  			Context:            ctxWithTenant,
   410  			ExpectedErrMessage: "while assigning formation with name",
   411  		},
   412  	}
   413  
   414  	for _, testCase := range testCases {
   415  		t.Run(testCase.Name, func(t *testing.T) {
   416  			repo := testCase.RuntimeContextRepositoryFn()
   417  			idSvc := testCase.UIDServiceFn()
   418  			formationSvc := testCase.FormationServiceFn()
   419  			tenantSvc := testCase.TenantServiceFN()
   420  			runtimeRepo := testCase.RuntimeRepositoryFn()
   421  			svc := runtimectx.NewService(repo, nil, runtimeRepo, nil, formationSvc, tenantSvc, idSvc)
   422  
   423  			// WHEN
   424  			result, err := svc.Create(testCase.Context, testCase.Input)
   425  
   426  			// THEN
   427  
   428  			if testCase.ExpectedErrMessage == "" {
   429  				require.Nil(t, err)
   430  				assert.IsType(t, "string", result)
   431  			} else {
   432  				require.NotNil(t, err)
   433  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   434  			}
   435  
   436  			mock.AssertExpectationsForObjects(t, repo, formationSvc, tenantSvc, idSvc, runtimeRepo)
   437  		})
   438  	}
   439  }
   440  
   441  func TestService_Update(t *testing.T) {
   442  	// GIVEN
   443  	testErr := errors.New("Test error")
   444  
   445  	id := "foo"
   446  	key := "key"
   447  	val := "value"
   448  	runtimeID := "runtime_id"
   449  
   450  	modelInput := model.RuntimeContextInput{
   451  		Key:       key,
   452  		Value:     val,
   453  		RuntimeID: runtimeID,
   454  	}
   455  
   456  	inputRuntimeContextModel := mock.MatchedBy(func(rtmCtx *model.RuntimeContext) bool {
   457  		return rtmCtx.Key == modelInput.Key && rtmCtx.Value == modelInput.Value && rtmCtx.RuntimeID == modelInput.RuntimeID
   458  	})
   459  
   460  	runtimeCtxModel := &model.RuntimeContext{
   461  		ID:        id,
   462  		Key:       key,
   463  		Value:     val,
   464  		RuntimeID: runtimeID,
   465  	}
   466  
   467  	tnt := "tenant"
   468  	externalTnt := "external-tnt"
   469  	ctxWithoutTenant := context.TODO()
   470  	ctxWithTenant := tenant.SaveToContext(ctxWithoutTenant, tnt, externalTnt)
   471  
   472  	testCases := []struct {
   473  		Name               string
   474  		RepositoryFn       func() *automock.RuntimeContextRepository
   475  		Input              model.RuntimeContextInput
   476  		InputID            string
   477  		Context            context.Context
   478  		ExpectedErrMessage string
   479  	}{
   480  		{
   481  			Name: "Success",
   482  			RepositoryFn: func() *automock.RuntimeContextRepository {
   483  				repo := &automock.RuntimeContextRepository{}
   484  				repo.On("GetByID", ctxWithTenant, tnt, "foo").Return(runtimeCtxModel, nil).Once()
   485  				repo.On("Update", ctxWithTenant, tnt, inputRuntimeContextModel).Return(nil).Once()
   486  				return repo
   487  			},
   488  			InputID:            id,
   489  			Input:              modelInput,
   490  			Context:            ctxWithTenant,
   491  			ExpectedErrMessage: "",
   492  		},
   493  		{
   494  			Name: "Returns error when runtime context update failed",
   495  			RepositoryFn: func() *automock.RuntimeContextRepository {
   496  				repo := &automock.RuntimeContextRepository{}
   497  				repo.On("GetByID", ctxWithTenant, tnt, "foo").Return(runtimeCtxModel, nil).Once()
   498  				repo.On("Update", ctxWithTenant, tnt, inputRuntimeContextModel).Return(testErr).Once()
   499  				return repo
   500  			},
   501  			InputID:            id,
   502  			Input:              modelInput,
   503  			Context:            ctxWithTenant,
   504  			ExpectedErrMessage: testErr.Error(),
   505  		},
   506  		{
   507  			Name: "Returns error when runtime context retrieval failed",
   508  			RepositoryFn: func() *automock.RuntimeContextRepository {
   509  				repo := &automock.RuntimeContextRepository{}
   510  				repo.On("GetByID", ctxWithTenant, tnt, "foo").Return(nil, testErr).Once()
   511  				return repo
   512  			},
   513  			InputID:            id,
   514  			Input:              modelInput,
   515  			Context:            ctxWithTenant,
   516  			ExpectedErrMessage: testErr.Error(),
   517  		},
   518  		{
   519  			Name: "Returns error when loading tenant from context failed",
   520  			RepositoryFn: func() *automock.RuntimeContextRepository {
   521  				repo := &automock.RuntimeContextRepository{}
   522  				return repo
   523  			},
   524  			InputID:            id,
   525  			Input:              model.RuntimeContextInput{},
   526  			Context:            ctxWithoutTenant,
   527  			ExpectedErrMessage: "while loading tenant from context: cannot read tenant from context",
   528  		},
   529  	}
   530  
   531  	for _, testCase := range testCases {
   532  		t.Run(testCase.Name, func(t *testing.T) {
   533  			repo := testCase.RepositoryFn()
   534  			svc := runtimectx.NewService(repo, nil, nil, nil, nil, nil, nil)
   535  
   536  			// WHEN
   537  			err := svc.Update(testCase.Context, testCase.InputID, testCase.Input)
   538  
   539  			// THEN
   540  			if testCase.ExpectedErrMessage == "" {
   541  				require.NoError(t, err)
   542  			} else {
   543  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   544  			}
   545  
   546  			repo.AssertExpectations(t)
   547  		})
   548  	}
   549  }
   550  
   551  func TestService_Delete(t *testing.T) {
   552  	// GIVEN
   553  	testErr := errors.New("Test error")
   554  	id := "foo"
   555  	key := "key"
   556  	val := "value"
   557  	runtimeID := "runtime_id"
   558  
   559  	scenario := "scenario"
   560  	runtimeCtxModel := &model.RuntimeContext{
   561  		ID:        id,
   562  		Key:       key,
   563  		Value:     val,
   564  		RuntimeID: runtimeID,
   565  	}
   566  
   567  	tnt := "tenant"
   568  	externalTnt := "external-tnt"
   569  	ctxWithoutTenant := context.TODO()
   570  	ctxWithTenant := tenant.SaveToContext(ctxWithoutTenant, tnt, externalTnt)
   571  
   572  	formations := []string{"scenario"}
   573  
   574  	testCases := []struct {
   575  		Name               string
   576  		RepositoryFn       func() *automock.RuntimeContextRepository
   577  		FormationServiceFN func() *automock.FormationService
   578  		Input              model.RuntimeContextInput
   579  		InputID            string
   580  		Context            context.Context
   581  		ExpectedErrMessage string
   582  	}{
   583  		{
   584  			Name: "Success",
   585  			RepositoryFn: func() *automock.RuntimeContextRepository {
   586  				repo := &automock.RuntimeContextRepository{}
   587  				repo.On("Delete", ctxWithTenant, tnt, runtimeCtxModel.ID).Return(nil).Once()
   588  				return repo
   589  			},
   590  			FormationServiceFN: func() *automock.FormationService {
   591  				formationSvc := &automock.FormationService{}
   592  				formationSvc.On("GetFormationsForObject", ctxWithTenant, tnt, model.RuntimeContextLabelableObject, id).Return(formations, nil).Once()
   593  				formationSvc.On("UnassignFormation", ctxWithTenant, tnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once()
   594  				return formationSvc
   595  			},
   596  			InputID:            id,
   597  			Context:            ctxWithTenant,
   598  			ExpectedErrMessage: "",
   599  		},
   600  		{
   601  			Name: "Returns error when loading tenant from context failed",
   602  			RepositoryFn: func() *automock.RuntimeContextRepository {
   603  				repo := &automock.RuntimeContextRepository{}
   604  				return repo
   605  			},
   606  			FormationServiceFN: unusedFormationService,
   607  			InputID:            id,
   608  			Context:            ctxWithoutTenant,
   609  			ExpectedErrMessage: "while loading tenant from context: cannot read tenant from context",
   610  		},
   611  		{
   612  			Name:         "Returns error when listing formations for runtime context",
   613  			RepositoryFn: unusedRuntimeContextRepo,
   614  			FormationServiceFN: func() *automock.FormationService {
   615  				formationSvc := &automock.FormationService{}
   616  				formationSvc.On("GetFormationsForObject", ctxWithTenant, tnt, model.RuntimeContextLabelableObject, id).Return(nil, testErr).Once()
   617  				return formationSvc
   618  			},
   619  			InputID:            id,
   620  			Context:            ctxWithTenant,
   621  			ExpectedErrMessage: "while listing formations for runtime context with id",
   622  		},
   623  		{
   624  			Name:         "Returns error while unassigning formation",
   625  			RepositoryFn: unusedRuntimeContextRepo,
   626  			FormationServiceFN: func() *automock.FormationService {
   627  				formationSvc := &automock.FormationService{}
   628  				formationSvc.On("GetFormationsForObject", ctxWithTenant, tnt, model.RuntimeContextLabelableObject, id).Return(formations, nil).Once()
   629  				formationSvc.On("UnassignFormation", ctxWithTenant, tnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, testErr).Once()
   630  				return formationSvc
   631  			},
   632  			InputID:            id,
   633  			Context:            ctxWithTenant,
   634  			ExpectedErrMessage: "while unassigning formation with name",
   635  		},
   636  		{
   637  			Name: "Returns error when runtime context deletion failed",
   638  			RepositoryFn: func() *automock.RuntimeContextRepository {
   639  				repo := &automock.RuntimeContextRepository{}
   640  				repo.On("Delete", ctxWithTenant, tnt, runtimeCtxModel.ID).Return(testErr).Once()
   641  				return repo
   642  			},
   643  			FormationServiceFN: func() *automock.FormationService {
   644  				formationSvc := &automock.FormationService{}
   645  				formationSvc.On("GetFormationsForObject", ctxWithTenant, tnt, model.RuntimeContextLabelableObject, id).Return(formations, nil).Once()
   646  				formationSvc.On("UnassignFormation", ctxWithTenant, tnt, id, graphql.FormationObjectTypeRuntimeContext, model.Formation{Name: scenario}).Return(nil, nil).Once()
   647  				return formationSvc
   648  			},
   649  			InputID:            id,
   650  			Context:            ctxWithTenant,
   651  			ExpectedErrMessage: testErr.Error(),
   652  		},
   653  	}
   654  
   655  	for _, testCase := range testCases {
   656  		t.Run(testCase.Name, func(t *testing.T) {
   657  			repo := testCase.RepositoryFn()
   658  			formationSvc := testCase.FormationServiceFN()
   659  			svc := runtimectx.NewService(repo, nil, nil, nil, formationSvc, nil, nil)
   660  
   661  			// WHEN
   662  			err := svc.Delete(testCase.Context, testCase.InputID)
   663  
   664  			// THEN
   665  			if testCase.ExpectedErrMessage == "" {
   666  				require.NoError(t, err)
   667  			} else {
   668  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   669  			}
   670  
   671  			mock.AssertExpectationsForObjects(t, repo, formationSvc)
   672  		})
   673  	}
   674  }
   675  
   676  func TestService_GetByID(t *testing.T) {
   677  	// GIVEN
   678  	testErr := errors.New("Test error")
   679  
   680  	id := "foo"
   681  	key := "key"
   682  	val := "value"
   683  	runtimeID := "runtime_id"
   684  	tnt := "tenant"
   685  	externalTnt := "external-tnt"
   686  
   687  	runtimeCtxModel := &model.RuntimeContext{
   688  		ID:        id,
   689  		Key:       key,
   690  		Value:     val,
   691  		RuntimeID: runtimeID,
   692  	}
   693  
   694  	ctx := context.TODO()
   695  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   696  
   697  	testCases := []struct {
   698  		Name                   string
   699  		RepositoryFn           func() *automock.RuntimeContextRepository
   700  		Input                  model.RuntimeContextInput
   701  		InputID                string
   702  		ExpectedRuntimeContext *model.RuntimeContext
   703  		ExpectedErrMessage     string
   704  	}{
   705  		{
   706  			Name: "Success",
   707  			RepositoryFn: func() *automock.RuntimeContextRepository {
   708  				repo := &automock.RuntimeContextRepository{}
   709  				repo.On("GetByID", ctx, tnt, id).Return(runtimeCtxModel, nil).Once()
   710  				return repo
   711  			},
   712  			InputID:                id,
   713  			ExpectedRuntimeContext: runtimeCtxModel,
   714  			ExpectedErrMessage:     "",
   715  		},
   716  		{
   717  			Name: "Returns error when runtime context retrieval failed",
   718  			RepositoryFn: func() *automock.RuntimeContextRepository {
   719  				repo := &automock.RuntimeContextRepository{}
   720  				repo.On("GetByID", ctx, tnt, id).Return(nil, testErr).Once()
   721  				return repo
   722  			},
   723  			InputID:                id,
   724  			ExpectedRuntimeContext: runtimeCtxModel,
   725  			ExpectedErrMessage:     testErr.Error(),
   726  		},
   727  	}
   728  
   729  	for _, testCase := range testCases {
   730  		t.Run(testCase.Name, func(t *testing.T) {
   731  			repo := testCase.RepositoryFn()
   732  
   733  			svc := runtimectx.NewService(repo, nil, nil, nil, nil, nil, nil)
   734  
   735  			// WHEN
   736  			rtmCtx, err := svc.GetByID(ctx, testCase.InputID)
   737  
   738  			// THEN
   739  			if testCase.ExpectedErrMessage == "" {
   740  				require.NoError(t, err)
   741  				assert.Equal(t, testCase.ExpectedRuntimeContext, rtmCtx)
   742  			} else {
   743  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   744  			}
   745  
   746  			repo.AssertExpectations(t)
   747  		})
   748  	}
   749  
   750  	t.Run("Returns error on loading tenant", func(t *testing.T) {
   751  		// GIVEN
   752  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
   753  		// WHEN
   754  		_, err := svc.GetByID(context.TODO(), "id")
   755  		// THEN
   756  		require.Error(t, err)
   757  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
   758  	})
   759  }
   760  
   761  func TestService_GetForRuntime(t *testing.T) {
   762  	// GIVEN
   763  	testErr := errors.New("Test error")
   764  
   765  	id := "foo"
   766  	key := "key"
   767  	val := "value"
   768  	runtimeID := "runtime_id"
   769  	tnt := "tenant"
   770  	externalTnt := "external-tnt"
   771  
   772  	runtimeCtxModel := &model.RuntimeContext{
   773  		ID:        id,
   774  		Key:       key,
   775  		Value:     val,
   776  		RuntimeID: runtimeID,
   777  	}
   778  
   779  	ctx := context.TODO()
   780  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   781  
   782  	testCases := []struct {
   783  		Name                   string
   784  		RepositoryFn           func() *automock.RuntimeContextRepository
   785  		Input                  model.RuntimeContextInput
   786  		InputID                string
   787  		ExpectedRuntimeContext *model.RuntimeContext
   788  		ExpectedErrMessage     string
   789  	}{
   790  		{
   791  			Name: "Success",
   792  			RepositoryFn: func() *automock.RuntimeContextRepository {
   793  				repo := &automock.RuntimeContextRepository{}
   794  				repo.On("GetForRuntime", ctx, tnt, id, runtimeID).Return(runtimeCtxModel, nil).Once()
   795  				return repo
   796  			},
   797  			InputID:                id,
   798  			ExpectedRuntimeContext: runtimeCtxModel,
   799  			ExpectedErrMessage:     "",
   800  		},
   801  		{
   802  			Name: "Returns error when runtime context retrieval failed",
   803  			RepositoryFn: func() *automock.RuntimeContextRepository {
   804  				repo := &automock.RuntimeContextRepository{}
   805  				repo.On("GetForRuntime", ctx, tnt, id, runtimeID).Return(nil, testErr).Once()
   806  				return repo
   807  			},
   808  			InputID:                id,
   809  			ExpectedRuntimeContext: runtimeCtxModel,
   810  			ExpectedErrMessage:     testErr.Error(),
   811  		},
   812  	}
   813  
   814  	for _, testCase := range testCases {
   815  		t.Run(testCase.Name, func(t *testing.T) {
   816  			repo := testCase.RepositoryFn()
   817  
   818  			svc := runtimectx.NewService(repo, nil, nil, nil, nil, nil, nil)
   819  
   820  			// WHEN
   821  			rtmCtx, err := svc.GetForRuntime(ctx, testCase.InputID, runtimeID)
   822  
   823  			// THEN
   824  			if testCase.ExpectedErrMessage == "" {
   825  				require.NoError(t, err)
   826  				assert.Equal(t, testCase.ExpectedRuntimeContext, rtmCtx)
   827  			} else {
   828  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   829  			}
   830  
   831  			repo.AssertExpectations(t)
   832  		})
   833  	}
   834  
   835  	t.Run("Returns error on loading tenant", func(t *testing.T) {
   836  		// GIVEN
   837  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
   838  		// WHEN
   839  		_, err := svc.GetForRuntime(context.TODO(), "id", runtimeID)
   840  		// THEN
   841  		require.Error(t, err)
   842  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
   843  	})
   844  }
   845  
   846  func TestService_ListAllForRuntime(t *testing.T) {
   847  	// GIVEN
   848  	testErr := errors.New("Test error")
   849  
   850  	runtimeID := "runtime_id"
   851  
   852  	id := "foo"
   853  	key := "key"
   854  	val := "value"
   855  
   856  	runtimeContexts := []*model.RuntimeContext{
   857  		{
   858  			ID:        id,
   859  			Key:       key,
   860  			Value:     val,
   861  			RuntimeID: runtimeID,
   862  		},
   863  	}
   864  
   865  	tnt := "tenant"
   866  	externalTnt := "external-tnt"
   867  
   868  	ctx := context.TODO()
   869  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   870  
   871  	testCases := []struct {
   872  		Name               string
   873  		RepositoryFn       func() *automock.RuntimeContextRepository
   874  		ExpectedResult     []*model.RuntimeContext
   875  		ExpectedErrMessage string
   876  	}{
   877  		{
   878  			Name: "Success",
   879  			RepositoryFn: func() *automock.RuntimeContextRepository {
   880  				repo := &automock.RuntimeContextRepository{}
   881  				repo.On("ListAllForRuntime", ctx, tnt, runtimeID).Return(runtimeContexts, nil).Once()
   882  				return repo
   883  			},
   884  			ExpectedResult:     runtimeContexts,
   885  			ExpectedErrMessage: "",
   886  		},
   887  		{
   888  			Name: "Returns error when runtime context listing failed",
   889  			RepositoryFn: func() *automock.RuntimeContextRepository {
   890  				repo := &automock.RuntimeContextRepository{}
   891  				repo.On("ListAllForRuntime", ctx, tnt, runtimeID).Return(nil, testErr).Once()
   892  				return repo
   893  			},
   894  			ExpectedResult:     nil,
   895  			ExpectedErrMessage: testErr.Error(),
   896  		},
   897  	}
   898  
   899  	for _, testCase := range testCases {
   900  		t.Run(testCase.Name, func(t *testing.T) {
   901  			repo := testCase.RepositoryFn()
   902  			svc := runtimectx.NewService(repo, nil, nil, nil, nil, nil, nil)
   903  
   904  			// WHEN
   905  			l, err := svc.ListAllForRuntime(ctx, runtimeID)
   906  
   907  			// THEN
   908  			if testCase.ExpectedErrMessage == "" {
   909  				require.NoError(t, err)
   910  				assert.Equal(t, l, testCase.ExpectedResult)
   911  			} else {
   912  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   913  			}
   914  
   915  			repo.AssertExpectations(t)
   916  		})
   917  	}
   918  
   919  	t.Run("Returns error on loading tenant", func(t *testing.T) {
   920  		// GIVEN
   921  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
   922  		// WHEN
   923  		_, err := svc.ListAllForRuntime(context.TODO(), runtimeID)
   924  		// THEN
   925  		require.Error(t, err)
   926  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
   927  	})
   928  }
   929  
   930  func TestService_ListByFilter(t *testing.T) {
   931  	// GIVEN
   932  	testErr := errors.New("Test error")
   933  
   934  	runtimeID := "runtime_id"
   935  
   936  	id := "foo"
   937  	key := "key"
   938  	val := "value"
   939  
   940  	id2 := "bar"
   941  	key2 := "key2"
   942  	val2 := "value2"
   943  
   944  	modelRuntimeContexts := []*model.RuntimeContext{
   945  		{
   946  			ID:        id,
   947  			Key:       key,
   948  			Value:     val,
   949  			RuntimeID: runtimeID,
   950  		},
   951  		{
   952  			ID:        id2,
   953  			Key:       key2,
   954  			Value:     val2,
   955  			RuntimeID: runtimeID,
   956  		},
   957  	}
   958  	runtimePage := &model.RuntimeContextPage{
   959  		Data:       modelRuntimeContexts,
   960  		TotalCount: len(modelRuntimeContexts),
   961  		PageInfo: &pagination.Page{
   962  			HasNextPage: false,
   963  			EndCursor:   "end",
   964  			StartCursor: "start",
   965  		},
   966  	}
   967  
   968  	first := 2
   969  	after := "test"
   970  	filter := []*labelfilter.LabelFilter{{Key: ""}}
   971  
   972  	tnt := "tenant"
   973  	externalTnt := "external-tnt"
   974  
   975  	ctx := context.TODO()
   976  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   977  
   978  	testCases := []struct {
   979  		Name               string
   980  		RepositoryFn       func() *automock.RuntimeContextRepository
   981  		InputLabelFilters  []*labelfilter.LabelFilter
   982  		InputPageSize      int
   983  		InputCursor        string
   984  		ExpectedResult     *model.RuntimeContextPage
   985  		ExpectedErrMessage string
   986  	}{
   987  		{
   988  			Name: "Success",
   989  			RepositoryFn: func() *automock.RuntimeContextRepository {
   990  				repo := &automock.RuntimeContextRepository{}
   991  				repo.On("List", ctx, runtimeID, tnt, filter, first, after).Return(runtimePage, nil).Once()
   992  				return repo
   993  			},
   994  			InputLabelFilters:  filter,
   995  			InputPageSize:      first,
   996  			InputCursor:        after,
   997  			ExpectedResult:     runtimePage,
   998  			ExpectedErrMessage: "",
   999  		},
  1000  		{
  1001  			Name: "Returns error when runtime context listing failed",
  1002  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1003  				repo := &automock.RuntimeContextRepository{}
  1004  				repo.On("List", ctx, runtimeID, tnt, filter, first, after).Return(nil, testErr).Once()
  1005  				return repo
  1006  			},
  1007  			InputLabelFilters:  filter,
  1008  			InputPageSize:      first,
  1009  			InputCursor:        after,
  1010  			ExpectedResult:     nil,
  1011  			ExpectedErrMessage: testErr.Error(),
  1012  		},
  1013  		{
  1014  			Name: "Returns error when pageSize is less than 1",
  1015  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1016  				repo := &automock.RuntimeContextRepository{}
  1017  				return repo
  1018  			},
  1019  			InputLabelFilters:  filter,
  1020  			InputPageSize:      0,
  1021  			InputCursor:        after,
  1022  			ExpectedResult:     nil,
  1023  			ExpectedErrMessage: "page size must be between 1 and 200",
  1024  		},
  1025  		{
  1026  			Name: "Returns error when pageSize is bigger than 200",
  1027  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1028  				repo := &automock.RuntimeContextRepository{}
  1029  				return repo
  1030  			},
  1031  			InputLabelFilters:  filter,
  1032  			InputPageSize:      201,
  1033  			InputCursor:        after,
  1034  			ExpectedResult:     nil,
  1035  			ExpectedErrMessage: "page size must be between 1 and 200",
  1036  		},
  1037  	}
  1038  
  1039  	for _, testCase := range testCases {
  1040  		t.Run(testCase.Name, func(t *testing.T) {
  1041  			repo := testCase.RepositoryFn()
  1042  
  1043  			svc := runtimectx.NewService(repo, nil, nil, nil, nil, nil, nil)
  1044  
  1045  			// WHEN
  1046  			rtmCtx, err := svc.ListByFilter(ctx, runtimeID, testCase.InputLabelFilters, testCase.InputPageSize, testCase.InputCursor)
  1047  
  1048  			// THEN
  1049  			if testCase.ExpectedErrMessage == "" {
  1050  				require.NoError(t, err)
  1051  				assert.Equal(t, testCase.ExpectedResult, rtmCtx)
  1052  			} else {
  1053  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  1054  			}
  1055  
  1056  			repo.AssertExpectations(t)
  1057  		})
  1058  	}
  1059  
  1060  	t.Run("Returns error on loading tenant", func(t *testing.T) {
  1061  		// GIVEN
  1062  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
  1063  		// WHEN
  1064  		_, err := svc.ListByFilter(context.TODO(), "", nil, 1, "")
  1065  		// THEN
  1066  		require.Error(t, err)
  1067  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
  1068  	})
  1069  }
  1070  
  1071  func TestService_ListByRuntimeIDs(t *testing.T) {
  1072  	// GIVEN
  1073  	testErr := errors.New("Test error")
  1074  
  1075  	runtimeID := "runtime_id"
  1076  	runtime2ID := "runtime2_id"
  1077  
  1078  	runtimeIDs := []string{runtimeID, runtime2ID}
  1079  
  1080  	id := "foo"
  1081  	key := "key"
  1082  	val := "value"
  1083  
  1084  	id2 := "bar"
  1085  	key2 := "key2"
  1086  	val2 := "value2"
  1087  
  1088  	modelRuntimeContexts := []*model.RuntimeContext{
  1089  		{
  1090  			ID:        id,
  1091  			Key:       key,
  1092  			Value:     val,
  1093  			RuntimeID: runtimeID,
  1094  		},
  1095  		{
  1096  			ID:        id2,
  1097  			Key:       key2,
  1098  			Value:     val2,
  1099  			RuntimeID: runtime2ID,
  1100  		},
  1101  	}
  1102  	runtimePage := &model.RuntimeContextPage{
  1103  		Data:       modelRuntimeContexts,
  1104  		TotalCount: len(modelRuntimeContexts),
  1105  		PageInfo: &pagination.Page{
  1106  			HasNextPage: false,
  1107  			EndCursor:   "end",
  1108  			StartCursor: "start",
  1109  		},
  1110  	}
  1111  
  1112  	first := 2
  1113  	after := "test"
  1114  
  1115  	tnt := "tenant"
  1116  	externalTnt := "external-tnt"
  1117  
  1118  	ctx := context.TODO()
  1119  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
  1120  
  1121  	testCases := []struct {
  1122  		Name               string
  1123  		RepositoryFn       func() *automock.RuntimeContextRepository
  1124  		InputPageSize      int
  1125  		InputCursor        string
  1126  		ExpectedResult     []*model.RuntimeContextPage
  1127  		ExpectedErrMessage string
  1128  	}{
  1129  		{
  1130  			Name: "Success",
  1131  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1132  				repo := &automock.RuntimeContextRepository{}
  1133  				repo.On("ListByRuntimeIDs", ctx, tnt, runtimeIDs, first, after).Return([]*model.RuntimeContextPage{runtimePage}, nil).Once()
  1134  				return repo
  1135  			},
  1136  			InputPageSize:      first,
  1137  			InputCursor:        after,
  1138  			ExpectedResult:     []*model.RuntimeContextPage{runtimePage},
  1139  			ExpectedErrMessage: "",
  1140  		},
  1141  		{
  1142  			Name: "Returns error when runtime context listing failed",
  1143  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1144  				repo := &automock.RuntimeContextRepository{}
  1145  				repo.On("ListByRuntimeIDs", ctx, tnt, runtimeIDs, first, after).Return(nil, testErr).Once()
  1146  				return repo
  1147  			},
  1148  			InputPageSize:      first,
  1149  			InputCursor:        after,
  1150  			ExpectedResult:     nil,
  1151  			ExpectedErrMessage: testErr.Error(),
  1152  		},
  1153  		{
  1154  			Name: "Returns error when pageSize is less than 1",
  1155  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1156  				repo := &automock.RuntimeContextRepository{}
  1157  				return repo
  1158  			},
  1159  			InputPageSize:      0,
  1160  			InputCursor:        after,
  1161  			ExpectedResult:     nil,
  1162  			ExpectedErrMessage: "page size must be between 1 and 200",
  1163  		},
  1164  		{
  1165  			Name: "Returns error when pageSize is bigger than 200",
  1166  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1167  				repo := &automock.RuntimeContextRepository{}
  1168  				return repo
  1169  			},
  1170  			InputPageSize:      201,
  1171  			InputCursor:        after,
  1172  			ExpectedResult:     nil,
  1173  			ExpectedErrMessage: "page size must be between 1 and 200",
  1174  		},
  1175  	}
  1176  
  1177  	for _, testCase := range testCases {
  1178  		t.Run(testCase.Name, func(t *testing.T) {
  1179  			repo := testCase.RepositoryFn()
  1180  
  1181  			svc := runtimectx.NewService(repo, nil, nil, nil, nil, nil, nil)
  1182  
  1183  			// WHEN
  1184  			rtmCtx, err := svc.ListByRuntimeIDs(ctx, runtimeIDs, testCase.InputPageSize, testCase.InputCursor)
  1185  
  1186  			// THEN
  1187  			if testCase.ExpectedErrMessage == "" {
  1188  				require.NoError(t, err)
  1189  				assert.Equal(t, testCase.ExpectedResult, rtmCtx)
  1190  			} else {
  1191  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  1192  			}
  1193  
  1194  			repo.AssertExpectations(t)
  1195  		})
  1196  	}
  1197  
  1198  	t.Run("Returns error on loading tenant", func(t *testing.T) {
  1199  		// GIVEN
  1200  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
  1201  		// WHEN
  1202  		_, err := svc.ListByRuntimeIDs(context.TODO(), runtimeIDs, 1, "")
  1203  		// THEN
  1204  		require.Error(t, err)
  1205  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
  1206  	})
  1207  }
  1208  
  1209  func TestService_ListLabel(t *testing.T) {
  1210  	// GIVEN
  1211  	tnt := "tenant"
  1212  	externalTnt := "external-tnt"
  1213  
  1214  	ctx := context.TODO()
  1215  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
  1216  
  1217  	testErr := errors.New("Test error")
  1218  
  1219  	runtimeCtxID := "foo"
  1220  	labelKey := "key"
  1221  	labelValue := []string{"value1"}
  1222  
  1223  	label := &model.LabelInput{
  1224  		Key:        labelKey,
  1225  		Value:      labelValue,
  1226  		ObjectID:   runtimeCtxID,
  1227  		ObjectType: model.RuntimeContextLabelableObject,
  1228  	}
  1229  
  1230  	modelLabel := &model.Label{
  1231  		ID:         "5d23d9d9-3d04-4fa9-95e6-d22e1ae62c11",
  1232  		Key:        labelKey,
  1233  		Value:      labelValue,
  1234  		ObjectID:   runtimeCtxID,
  1235  		ObjectType: model.RuntimeContextLabelableObject,
  1236  	}
  1237  
  1238  	labels := map[string]*model.Label{"first": modelLabel, "second": modelLabel}
  1239  	testCases := []struct {
  1240  		Name                  string
  1241  		RepositoryFn          func() *automock.RuntimeContextRepository
  1242  		LabelRepositoryFn     func() *automock.LabelRepository
  1243  		InputRuntimeContextID string
  1244  		InputLabel            *model.LabelInput
  1245  		ExpectedOutput        map[string]*model.Label
  1246  		ExpectedErrMessage    string
  1247  	}{
  1248  		{
  1249  			Name: "Success",
  1250  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1251  				repo := &automock.RuntimeContextRepository{}
  1252  				repo.On("Exists", ctx, tnt, runtimeCtxID).Return(true, nil).Once()
  1253  				return repo
  1254  			},
  1255  			LabelRepositoryFn: func() *automock.LabelRepository {
  1256  				repo := &automock.LabelRepository{}
  1257  				repo.On("ListForObject", ctx, tnt, model.RuntimeContextLabelableObject, runtimeCtxID).Return(labels, nil).Once()
  1258  				return repo
  1259  			},
  1260  			InputRuntimeContextID: runtimeCtxID,
  1261  			InputLabel:            label,
  1262  			ExpectedOutput:        labels,
  1263  			ExpectedErrMessage:    "",
  1264  		},
  1265  		{
  1266  			Name: "Returns error when labels receiving failed",
  1267  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1268  				repo := &automock.RuntimeContextRepository{}
  1269  				repo.On("Exists", ctx, tnt, runtimeCtxID).Return(true, nil).Once()
  1270  
  1271  				return repo
  1272  			},
  1273  			LabelRepositoryFn: func() *automock.LabelRepository {
  1274  				repo := &automock.LabelRepository{}
  1275  				repo.On("ListForObject", ctx, tnt, model.RuntimeContextLabelableObject, runtimeCtxID).Return(nil, testErr).Once()
  1276  				return repo
  1277  			},
  1278  			InputRuntimeContextID: runtimeCtxID,
  1279  			InputLabel:            label,
  1280  			ExpectedOutput:        nil,
  1281  			ExpectedErrMessage:    testErr.Error(),
  1282  		},
  1283  		{
  1284  			Name: "Returns error when runtime context exists function failed",
  1285  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1286  				repo := &automock.RuntimeContextRepository{}
  1287  				repo.On("Exists", ctx, tnt, runtimeCtxID).Return(false, testErr).Once()
  1288  
  1289  				return repo
  1290  			},
  1291  			LabelRepositoryFn: func() *automock.LabelRepository {
  1292  				repo := &automock.LabelRepository{}
  1293  				return repo
  1294  			},
  1295  			InputRuntimeContextID: runtimeCtxID,
  1296  			InputLabel:            label,
  1297  			ExpectedErrMessage:    testErr.Error(),
  1298  		},
  1299  		{
  1300  			Name: "Returns error when runtime context does not exists",
  1301  			RepositoryFn: func() *automock.RuntimeContextRepository {
  1302  				repo := &automock.RuntimeContextRepository{}
  1303  				repo.On("Exists", ctx, tnt, runtimeCtxID).Return(false, nil).Once()
  1304  
  1305  				return repo
  1306  			},
  1307  			LabelRepositoryFn: func() *automock.LabelRepository {
  1308  				repo := &automock.LabelRepository{}
  1309  				return repo
  1310  			},
  1311  			InputRuntimeContextID: runtimeCtxID,
  1312  			InputLabel:            label,
  1313  			ExpectedErrMessage:    fmt.Sprintf("runtime Context with ID %s doesn't exist", runtimeCtxID),
  1314  		},
  1315  	}
  1316  
  1317  	for _, testCase := range testCases {
  1318  		t.Run(testCase.Name, func(t *testing.T) {
  1319  			repo := testCase.RepositoryFn()
  1320  			labelRepo := testCase.LabelRepositoryFn()
  1321  			svc := runtimectx.NewService(repo, labelRepo, nil, nil, nil, nil, nil)
  1322  
  1323  			// WHEN
  1324  			l, err := svc.ListLabels(ctx, testCase.InputRuntimeContextID)
  1325  
  1326  			// THEN
  1327  			if testCase.ExpectedErrMessage == "" {
  1328  				require.NoError(t, err)
  1329  				assert.Equal(t, l, testCase.ExpectedOutput)
  1330  			} else {
  1331  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  1332  			}
  1333  
  1334  			repo.AssertExpectations(t)
  1335  			labelRepo.AssertExpectations(t)
  1336  		})
  1337  	}
  1338  
  1339  	t.Run("Returns error on loading tenant", func(t *testing.T) {
  1340  		// GIVEN
  1341  		svc := runtimectx.NewService(nil, nil, nil, nil, nil, nil, nil)
  1342  		// WHEN
  1343  		_, err := svc.ListLabels(context.TODO(), "id")
  1344  		// THEN
  1345  		require.Error(t, err)
  1346  		assert.EqualError(t, err, "while loading tenant from context: cannot read tenant from context")
  1347  	})
  1348  }
  1349  
  1350  func unusedRuntimeContextRepo() *automock.RuntimeContextRepository {
  1351  	return &automock.RuntimeContextRepository{}
  1352  }
  1353  
  1354  func unusedUIDService() *automock.UIDService {
  1355  	return &automock.UIDService{}
  1356  }
  1357  
  1358  func unusedFormationService() *automock.FormationService {
  1359  	return &automock.FormationService{}
  1360  }
  1361  
  1362  func unusedTenantService() *automock.TenantService {
  1363  	return &automock.TenantService{}
  1364  }
  1365  
  1366  func unusedRuntimeRepo() *automock.RuntimeRepository {
  1367  	return &automock.RuntimeRepository{}
  1368  }