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

     1  package bundleinstanceauth_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/pkg/consumer"
     9  
    10  	"github.com/kyma-incubator/compass/components/director/internal/domain/bundleinstanceauth"
    11  	"github.com/kyma-incubator/compass/components/director/internal/domain/bundleinstanceauth/automock"
    12  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    13  	"github.com/kyma-incubator/compass/components/director/internal/model"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    15  
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/mock"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func TestService_Get(t *testing.T) {
    23  	// GIVEN
    24  	tnt := testTenant
    25  	externalTnt := "external-tnt"
    26  	ctx := context.TODO()
    27  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
    28  
    29  	id := "foo"
    30  
    31  	modelInstanceAuth := fixSimpleModelBundleInstanceAuth(id)
    32  
    33  	testErr := errors.New("test error")
    34  
    35  	testCases := []struct {
    36  		Name               string
    37  		instanceAuthRepoFn func() *automock.Repository
    38  		ExpectedOutput     *model.BundleInstanceAuth
    39  		ExpectedError      error
    40  	}{
    41  		{
    42  			Name: "Success",
    43  			instanceAuthRepoFn: func() *automock.Repository {
    44  				instanceAuthRepo := &automock.Repository{}
    45  				instanceAuthRepo.On("GetByID", contextThatHasTenant(tnt), tnt, id).Return(modelInstanceAuth, nil).Once()
    46  				return instanceAuthRepo
    47  			},
    48  			ExpectedOutput: modelInstanceAuth,
    49  			ExpectedError:  nil,
    50  		},
    51  		{
    52  			Name: "Error",
    53  			instanceAuthRepoFn: func() *automock.Repository {
    54  				instanceAuthRepo := &automock.Repository{}
    55  				instanceAuthRepo.On("GetByID", contextThatHasTenant(tnt), tnt, id).Return(nil, testErr).Once()
    56  				return instanceAuthRepo
    57  			},
    58  			ExpectedOutput: nil,
    59  			ExpectedError:  testErr,
    60  		},
    61  	}
    62  
    63  	for _, testCase := range testCases {
    64  		t.Run(testCase.Name, func(t *testing.T) {
    65  			instanceAuthRepo := testCase.instanceAuthRepoFn()
    66  
    67  			svc := bundleinstanceauth.NewService(instanceAuthRepo, nil)
    68  
    69  			// WHEN
    70  			result, err := svc.Get(ctx, id)
    71  
    72  			// THEN
    73  			if testCase.ExpectedError != nil {
    74  				require.Error(t, err)
    75  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
    76  			} else {
    77  				assert.NoError(t, err)
    78  			}
    79  			assert.Equal(t, testCase.ExpectedOutput, result)
    80  
    81  			instanceAuthRepo.AssertExpectations(t)
    82  		})
    83  	}
    84  
    85  	t.Run("Error when tenant not in context", func(t *testing.T) {
    86  		svc := bundleinstanceauth.NewService(nil, nil)
    87  
    88  		// WHEN
    89  		_, err := svc.Get(context.TODO(), id)
    90  
    91  		// THEN
    92  		require.Error(t, err)
    93  		assert.Contains(t, err.Error(), "cannot read tenant from context")
    94  	})
    95  }
    96  
    97  func TestService_GetForBundle(t *testing.T) {
    98  	// GIVEN
    99  	tnt := testTenant
   100  	externalTnt := testExternalTenant
   101  
   102  	ctx := context.TODO()
   103  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   104  
   105  	id := "foo"
   106  	bundleID := "bar"
   107  
   108  	modelInstanceAuth := fixSimpleModelBundleInstanceAuth(id)
   109  
   110  	testErr := errors.New("test error")
   111  
   112  	testCases := []struct {
   113  		Name               string
   114  		instanceAuthRepoFn func() *automock.Repository
   115  		ExpectedOutput     *model.BundleInstanceAuth
   116  		ExpectedError      error
   117  	}{
   118  		{
   119  			Name: "Success",
   120  			instanceAuthRepoFn: func() *automock.Repository {
   121  				instanceAuthRepo := &automock.Repository{}
   122  				instanceAuthRepo.On("GetForBundle", contextThatHasTenant(tnt), tnt, id, bundleID).Return(modelInstanceAuth, nil).Once()
   123  				return instanceAuthRepo
   124  			},
   125  			ExpectedOutput: modelInstanceAuth,
   126  			ExpectedError:  nil,
   127  		},
   128  		{
   129  			Name: "Error",
   130  			instanceAuthRepoFn: func() *automock.Repository {
   131  				instanceAuthRepo := &automock.Repository{}
   132  				instanceAuthRepo.On("GetForBundle", contextThatHasTenant(tnt), tnt, id, bundleID).Return(nil, testErr).Once()
   133  				return instanceAuthRepo
   134  			},
   135  			ExpectedOutput: nil,
   136  			ExpectedError:  testErr,
   137  		},
   138  	}
   139  
   140  	for _, testCase := range testCases {
   141  		t.Run(testCase.Name, func(t *testing.T) {
   142  			instanceAuthRepo := testCase.instanceAuthRepoFn()
   143  
   144  			svc := bundleinstanceauth.NewService(instanceAuthRepo, nil)
   145  
   146  			// WHEN
   147  			result, err := svc.GetForBundle(ctx, id, bundleID)
   148  
   149  			// THEN
   150  			if testCase.ExpectedError != nil {
   151  				require.Error(t, err)
   152  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   153  			} else {
   154  				assert.NoError(t, err)
   155  			}
   156  			assert.Equal(t, testCase.ExpectedOutput, result)
   157  
   158  			instanceAuthRepo.AssertExpectations(t)
   159  		})
   160  	}
   161  
   162  	t.Run("Error when tenant not in context", func(t *testing.T) {
   163  		svc := bundleinstanceauth.NewService(nil, nil)
   164  
   165  		// WHEN
   166  		_, err := svc.GetForBundle(context.TODO(), id, bundleID)
   167  
   168  		// THEN
   169  		require.Error(t, err)
   170  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   171  	})
   172  }
   173  
   174  func TestService_Delete(t *testing.T) {
   175  	// GIVEN
   176  	tnt := testTenant
   177  	externalTnt := testExternalTenant
   178  
   179  	ctx := context.TODO()
   180  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   181  
   182  	id := "foo"
   183  
   184  	testErr := errors.New("test error")
   185  
   186  	testCases := []struct {
   187  		Name               string
   188  		instanceAuthRepoFn func() *automock.Repository
   189  		ExpectedError      error
   190  	}{
   191  		{
   192  			Name: "Success",
   193  			instanceAuthRepoFn: func() *automock.Repository {
   194  				instanceAuthRepo := &automock.Repository{}
   195  				instanceAuthRepo.On("Delete", contextThatHasTenant(tnt), tnt, id).Return(nil).Once()
   196  				return instanceAuthRepo
   197  			},
   198  			ExpectedError: nil,
   199  		},
   200  		{
   201  			Name: "Error",
   202  			instanceAuthRepoFn: func() *automock.Repository {
   203  				instanceAuthRepo := &automock.Repository{}
   204  				instanceAuthRepo.On("Delete", contextThatHasTenant(tnt), tnt, id).Return(testErr).Once()
   205  				return instanceAuthRepo
   206  			},
   207  			ExpectedError: testErr,
   208  		},
   209  	}
   210  
   211  	for _, testCase := range testCases {
   212  		t.Run(testCase.Name, func(t *testing.T) {
   213  			instanceAuthRepo := testCase.instanceAuthRepoFn()
   214  
   215  			svc := bundleinstanceauth.NewService(instanceAuthRepo, nil)
   216  
   217  			// WHEN
   218  			err := svc.Delete(ctx, id)
   219  
   220  			// THEN
   221  			if testCase.ExpectedError != nil {
   222  				require.Error(t, err)
   223  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   224  			} else {
   225  				assert.NoError(t, err)
   226  			}
   227  
   228  			instanceAuthRepo.AssertExpectations(t)
   229  		})
   230  	}
   231  
   232  	t.Run("Error when tenant not in context", func(t *testing.T) {
   233  		svc := bundleinstanceauth.NewService(nil, nil)
   234  
   235  		// WHEN
   236  		err := svc.Delete(context.TODO(), id)
   237  
   238  		// THEN
   239  		require.Error(t, err)
   240  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   241  	})
   242  }
   243  
   244  func TestService_SetAuth(t *testing.T) {
   245  	// GIVEN
   246  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   247  
   248  	modelInstanceAuthFn := func() *model.BundleInstanceAuth {
   249  		return fixModelBundleInstanceAuth(testID, testBundleID, testTenant, nil, fixModelStatusPending(), nil)
   250  	}
   251  
   252  	modelSetInput := fixModelSetInput()
   253  	modelUpdatedInstanceAuth := fixModelBundleInstanceAuth(testID, testBundleID, testTenant, nil, fixModelStatusPending(), nil)
   254  	modelUpdatedInstanceAuth.Auth = modelSetInput.Auth.ToAuth()
   255  	modelUpdatedInstanceAuth.Status = &model.BundleInstanceAuthStatus{
   256  		Condition: model.BundleInstanceAuthStatusConditionSucceeded,
   257  		Timestamp: testTime,
   258  		Message:   modelSetInput.Status.Message,
   259  		Reason:    modelSetInput.Status.Reason,
   260  	}
   261  
   262  	modelSetInputWithoutStatus := model.BundleInstanceAuthSetInput{
   263  		Auth:   fixModelAuthInput(),
   264  		Status: nil,
   265  	}
   266  	modelUpdatedInstanceAuthWithDefaultStatus := fixModelBundleInstanceAuth(testID, testBundleID, testTenant, nil, fixModelStatusPending(), nil)
   267  	modelUpdatedInstanceAuthWithDefaultStatus.Auth = modelSetInputWithoutStatus.Auth.ToAuth()
   268  	err := modelUpdatedInstanceAuthWithDefaultStatus.SetDefaultStatus(model.BundleInstanceAuthStatusConditionSucceeded, testTime)
   269  	require.NoError(t, err)
   270  
   271  	testCases := []struct {
   272  		Name               string
   273  		InstanceAuthRepoFn func() *automock.Repository
   274  		Input              model.BundleInstanceAuthSetInput
   275  		ExpectedError      error
   276  	}{
   277  		{
   278  			Name: "Success",
   279  			InstanceAuthRepoFn: func() *automock.Repository {
   280  				instanceAuthRepo := &automock.Repository{}
   281  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(modelInstanceAuthFn(), nil).Once()
   282  				instanceAuthRepo.On("Update", contextThatHasTenant(testTenant), testTenant, modelUpdatedInstanceAuth).Return(nil).Once()
   283  				return instanceAuthRepo
   284  			},
   285  			Input:         *modelSetInput,
   286  			ExpectedError: nil,
   287  		},
   288  		{
   289  			Name: "Success when new status not provided",
   290  			InstanceAuthRepoFn: func() *automock.Repository {
   291  				instanceAuthRepo := &automock.Repository{}
   292  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(modelInstanceAuthFn(), nil).Once()
   293  				instanceAuthRepo.On("Update", contextThatHasTenant(testTenant), testTenant, modelUpdatedInstanceAuthWithDefaultStatus).Return(nil).Once()
   294  				return instanceAuthRepo
   295  			},
   296  			Input:         modelSetInputWithoutStatus,
   297  			ExpectedError: nil,
   298  		},
   299  		{
   300  			Name: "Error when Bundle Instance Auth retrieval failed",
   301  			InstanceAuthRepoFn: func() *automock.Repository {
   302  				instanceAuthRepo := &automock.Repository{}
   303  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(modelInstanceAuthFn(), testError).Once()
   304  				return instanceAuthRepo
   305  			},
   306  			Input:         *modelSetInput,
   307  			ExpectedError: testError,
   308  		},
   309  		{
   310  			Name: "Error when Bundle Instance Auth update failed",
   311  			InstanceAuthRepoFn: func() *automock.Repository {
   312  				instanceAuthRepo := &automock.Repository{}
   313  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(modelInstanceAuthFn(), nil).Once()
   314  				instanceAuthRepo.On("Update", contextThatHasTenant(testTenant), testTenant, modelUpdatedInstanceAuth).Return(testError).Once()
   315  				return instanceAuthRepo
   316  			},
   317  			Input:         *modelSetInput,
   318  			ExpectedError: testError,
   319  		},
   320  		{
   321  			Name: "Error when Bundle Instance Auth status is nil",
   322  			InstanceAuthRepoFn: func() *automock.Repository {
   323  				instanceAuthRepo := &automock.Repository{}
   324  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(
   325  					&model.BundleInstanceAuth{
   326  						Status: nil,
   327  					}, nil).Once()
   328  				return instanceAuthRepo
   329  			},
   330  			Input:         *modelSetInput,
   331  			ExpectedError: errors.New("auth can be set only on BundleInstanceAuths in PENDING state"),
   332  		},
   333  		{
   334  			Name: "Error when Bundle Instance Auth status condition different from PENDING",
   335  			InstanceAuthRepoFn: func() *automock.Repository {
   336  				instanceAuthRepo := &automock.Repository{}
   337  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(
   338  					&model.BundleInstanceAuth{
   339  						Status: &model.BundleInstanceAuthStatus{
   340  							Condition: model.BundleInstanceAuthStatusConditionSucceeded,
   341  						},
   342  					}, nil).Once()
   343  				return instanceAuthRepo
   344  			},
   345  			Input:         *modelSetInput,
   346  			ExpectedError: errors.New("auth can be set only on BundleInstanceAuths in PENDING state"),
   347  		},
   348  		{
   349  			Name: "Error when retrieved Bundle Instance Auth is nil",
   350  			InstanceAuthRepoFn: func() *automock.Repository {
   351  				instanceAuthRepo := &automock.Repository{}
   352  				instanceAuthRepo.On("GetByID", contextThatHasTenant(testTenant), testTenant, testID).Return(nil, nil).Once()
   353  
   354  				return instanceAuthRepo
   355  			},
   356  			Input:         *modelSetInput,
   357  			ExpectedError: errors.Errorf("BundleInstanceAuth with id %s not found", testID),
   358  		},
   359  	}
   360  
   361  	for _, testCase := range testCases {
   362  		t.Run(testCase.Name, func(t *testing.T) {
   363  			instanceAuthRepo := testCase.InstanceAuthRepoFn()
   364  
   365  			svc := bundleinstanceauth.NewService(instanceAuthRepo, nil)
   366  			svc.SetTimestampGen(func() time.Time { return testTime })
   367  
   368  			// WHEN
   369  			err := svc.SetAuth(ctx, testID, testCase.Input)
   370  
   371  			// THEN
   372  			if testCase.ExpectedError != nil {
   373  				require.Error(t, err)
   374  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   375  			} else {
   376  				assert.NoError(t, err)
   377  			}
   378  
   379  			mock.AssertExpectationsForObjects(t, instanceAuthRepo)
   380  		})
   381  	}
   382  
   383  	t.Run("Error when tenant not in context", func(t *testing.T) {
   384  		svc := bundleinstanceauth.NewService(nil, nil)
   385  
   386  		// WHEN
   387  		err := svc.SetAuth(context.TODO(), testID, model.BundleInstanceAuthSetInput{})
   388  
   389  		// THEN
   390  		require.Error(t, err)
   391  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   392  	})
   393  }
   394  
   395  func TestService_Create(t *testing.T) {
   396  	// GIVEN
   397  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   398  
   399  	consumerEntity := consumer.Consumer{
   400  		ConsumerID:   testRuntimeID,
   401  		ConsumerType: consumer.Runtime,
   402  	}
   403  	ctx = consumer.SaveToContext(ctx, consumerEntity)
   404  
   405  	modelAuth := fixModelAuth()
   406  	modelExpectedInstanceAuth := fixModelBundleInstanceAuth(testID, testBundleID, testTenant, modelAuth, fixModelStatusSucceeded(), &testRuntimeID)
   407  	modelExpectedInstanceAuthPending := fixModelBundleInstanceAuth(testID, testBundleID, testTenant, nil, fixModelStatusPending(), &testRuntimeID)
   408  
   409  	modelRequestInput := fixModelRequestInput()
   410  
   411  	testCases := []struct {
   412  		Name               string
   413  		InstanceAuthRepoFn func() *automock.Repository
   414  		UIDSvcFn           func() *automock.UIDService
   415  		Input              model.BundleInstanceAuthRequestInput
   416  		InputAuth          *model.Auth
   417  		InputSchema        *string
   418  		ExpectedOutput     string
   419  		ExpectedError      error
   420  	}{
   421  		{
   422  			Name: "Success",
   423  			InstanceAuthRepoFn: func() *automock.Repository {
   424  				instanceAuthRepo := &automock.Repository{}
   425  				instanceAuthRepo.On("Create", contextThatHasTenant(testTenant), modelExpectedInstanceAuth).Return(nil).Once()
   426  				return instanceAuthRepo
   427  			},
   428  			UIDSvcFn: func() *automock.UIDService {
   429  				svc := automock.UIDService{}
   430  				svc.On("Generate").Return(testID).Once()
   431  				return &svc
   432  			},
   433  			Input:          *modelRequestInput,
   434  			InputAuth:      modelAuth,
   435  			InputSchema:    nil,
   436  			ExpectedOutput: testID,
   437  			ExpectedError:  nil,
   438  		},
   439  		{
   440  			Name: "Success when input auth is nil",
   441  			InstanceAuthRepoFn: func() *automock.Repository {
   442  				instanceAuthRepo := &automock.Repository{}
   443  				instanceAuthRepo.On("Create", contextThatHasTenant(testTenant), modelExpectedInstanceAuthPending).Return(nil).Once()
   444  				return instanceAuthRepo
   445  			},
   446  			UIDSvcFn: func() *automock.UIDService {
   447  				svc := automock.UIDService{}
   448  				svc.On("Generate").Return(testID).Once()
   449  				return &svc
   450  			},
   451  			Input:          *modelRequestInput,
   452  			InputAuth:      nil,
   453  			InputSchema:    nil,
   454  			ExpectedOutput: testID,
   455  			ExpectedError:  nil,
   456  		},
   457  		{
   458  			Name: "Success when schema provided",
   459  			InstanceAuthRepoFn: func() *automock.Repository {
   460  				instanceAuthRepo := &automock.Repository{}
   461  				instanceAuthRepo.On("Create", contextThatHasTenant(testTenant), modelExpectedInstanceAuth).Return(nil).Once()
   462  				return instanceAuthRepo
   463  			},
   464  			UIDSvcFn: func() *automock.UIDService {
   465  				svc := automock.UIDService{}
   466  				svc.On("Generate").Return(testID).Once()
   467  				return &svc
   468  			},
   469  			Input:          *modelRequestInput,
   470  			InputAuth:      modelAuth,
   471  			InputSchema:    str.Ptr("{\"type\": \"object\"}"),
   472  			ExpectedOutput: testID,
   473  			ExpectedError:  nil,
   474  		},
   475  		{
   476  			Name: "Error when creating Bundle Instance Auth",
   477  			InstanceAuthRepoFn: func() *automock.Repository {
   478  				instanceAuthRepo := &automock.Repository{}
   479  				instanceAuthRepo.On("Create", contextThatHasTenant(testTenant), modelExpectedInstanceAuth).Return(testError).Once()
   480  				return instanceAuthRepo
   481  			},
   482  			UIDSvcFn: func() *automock.UIDService {
   483  				svc := automock.UIDService{}
   484  				svc.On("Generate").Return(testID).Once()
   485  				return &svc
   486  			},
   487  			Input:          *modelRequestInput,
   488  			InputAuth:      modelAuth,
   489  			InputSchema:    nil,
   490  			ExpectedOutput: "",
   491  			ExpectedError:  testError,
   492  		},
   493  		{
   494  			Name: "Error when schema defined but no input params provided",
   495  			InstanceAuthRepoFn: func() *automock.Repository {
   496  				instanceAuthRepo := &automock.Repository{}
   497  				return instanceAuthRepo
   498  			},
   499  			UIDSvcFn: func() *automock.UIDService {
   500  				svc := automock.UIDService{}
   501  				return &svc
   502  			},
   503  			Input:          model.BundleInstanceAuthRequestInput{},
   504  			InputAuth:      modelAuth,
   505  			InputSchema:    str.Ptr("{\"type\": \"string\"}"),
   506  			ExpectedOutput: "",
   507  			ExpectedError:  errors.New("json schema for input parameters was defined for the bundle but no input parameters were provided"),
   508  		},
   509  		{
   510  			Name: "Error when invalid schema provided",
   511  			InstanceAuthRepoFn: func() *automock.Repository {
   512  				instanceAuthRepo := &automock.Repository{}
   513  				return instanceAuthRepo
   514  			},
   515  			UIDSvcFn: func() *automock.UIDService {
   516  				svc := automock.UIDService{}
   517  				return &svc
   518  			},
   519  			Input:          *modelRequestInput,
   520  			InputAuth:      modelAuth,
   521  			InputSchema:    str.Ptr("error"),
   522  			ExpectedOutput: "",
   523  			ExpectedError:  errors.New("while creating JSON Schema validator for schema error: invalid character 'e' looking for beginning of value"),
   524  		},
   525  		{
   526  			Name: "Error when invalid input params",
   527  			InstanceAuthRepoFn: func() *automock.Repository {
   528  				instanceAuthRepo := &automock.Repository{}
   529  				return instanceAuthRepo
   530  			},
   531  			UIDSvcFn: func() *automock.UIDService {
   532  				svc := automock.UIDService{}
   533  				return &svc
   534  			},
   535  			Input: model.BundleInstanceAuthRequestInput{
   536  				InputParams: str.Ptr("{"),
   537  			},
   538  			InputAuth:      modelAuth,
   539  			InputSchema:    str.Ptr("{\"type\": \"string\"}"),
   540  			ExpectedOutput: "",
   541  			ExpectedError:  errors.New(`while validating value { against JSON Schema: {"type": "string"}: unexpected EOF`),
   542  		},
   543  		{
   544  			Name: "Error when input doesn't match schema",
   545  			InstanceAuthRepoFn: func() *automock.Repository {
   546  				instanceAuthRepo := &automock.Repository{}
   547  				return instanceAuthRepo
   548  			},
   549  			UIDSvcFn: func() *automock.UIDService {
   550  				svc := automock.UIDService{}
   551  				return &svc
   552  			},
   553  			Input:          *modelRequestInput,
   554  			InputAuth:      modelAuth,
   555  			InputSchema:    str.Ptr("{\"type\": \"string\"}"),
   556  			ExpectedOutput: "",
   557  			ExpectedError:  errors.New(`while validating value {"bar": "baz"} against JSON Schema: {"type": "string"}: (root): Invalid type. Expected: string, given: object`),
   558  		},
   559  	}
   560  
   561  	for _, testCase := range testCases {
   562  		t.Run(testCase.Name, func(t *testing.T) {
   563  			instanceAuthRepo := testCase.InstanceAuthRepoFn()
   564  			uidSvc := testCase.UIDSvcFn()
   565  
   566  			svc := bundleinstanceauth.NewService(instanceAuthRepo, uidSvc)
   567  			svc.SetTimestampGen(func() time.Time { return testTime })
   568  
   569  			// WHEN
   570  			result, err := svc.Create(ctx, testBundleID, testCase.Input, testCase.InputAuth, testCase.InputSchema)
   571  
   572  			// THEN
   573  			if testCase.ExpectedError != nil {
   574  				require.Error(t, err)
   575  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   576  			} else {
   577  				assert.NoError(t, err)
   578  			}
   579  			assert.Equal(t, testCase.ExpectedOutput, result)
   580  
   581  			mock.AssertExpectationsForObjects(t, instanceAuthRepo, uidSvc)
   582  		})
   583  	}
   584  
   585  	t.Run("Error when tenant not in context", func(t *testing.T) {
   586  		svc := bundleinstanceauth.NewService(nil, nil)
   587  
   588  		// WHEN
   589  		_, err := svc.Create(context.TODO(), testBundleID, model.BundleInstanceAuthRequestInput{}, nil, nil)
   590  
   591  		// THEN
   592  		require.Error(t, err)
   593  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   594  	})
   595  
   596  	t.Run("Error when consumer is not in the context", func(t *testing.T) {
   597  		// GIVEN
   598  		svc := bundleinstanceauth.NewService(nil, nil)
   599  		ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   600  
   601  		// WHEN
   602  		_, err := svc.Create(ctx, testBundleID, *modelRequestInput, modelAuth, nil)
   603  
   604  		// THEN
   605  		require.Error(t, err)
   606  		assert.Contains(t, err.Error(), "cannot read consumer from context")
   607  	})
   608  }
   609  
   610  func TestService_CreateBundleInstanceAuth(t *testing.T) {
   611  	// GIVEN
   612  	ctx := tenant.SaveToContext(context.TODO(), testTenant, testExternalTenant)
   613  
   614  	consumerEntity := consumer.Consumer{
   615  		ConsumerID:   testRuntimeID,
   616  		ConsumerType: consumer.Runtime,
   617  	}
   618  	ctx = consumer.SaveToContext(ctx, consumerEntity)
   619  
   620  	modelCreateInput := fixModelCreateInput()
   621  	modelExpectedInstanceAuth := fixModelBundleInstanceAuth(testID, testBundleID, testTenant, fixModelAuthInput().ToAuth(), fixModelStatusSucceeded(), &testRuntimeID)
   622  
   623  	testCases := []struct {
   624  		Name               string
   625  		InstanceAuthRepoFn func() *automock.Repository
   626  		UIDSvcFn           func() *automock.UIDService
   627  		Input              model.BundleInstanceAuthCreateInput
   628  		InputSchema        *string
   629  		ExpectedOutput     string
   630  		ExpectedError      error
   631  	}{
   632  		{
   633  			Name: "Success",
   634  			InstanceAuthRepoFn: func() *automock.Repository {
   635  				instanceAuthRepo := &automock.Repository{}
   636  				instanceAuthRepo.On("Create", contextThatHasTenant(testTenant), modelExpectedInstanceAuth).Return(nil).Once()
   637  				return instanceAuthRepo
   638  			},
   639  			UIDSvcFn: func() *automock.UIDService {
   640  				svc := automock.UIDService{}
   641  				svc.On("Generate").Return(testID).Once()
   642  				return &svc
   643  			},
   644  			Input:          *modelCreateInput,
   645  			InputSchema:    nil,
   646  			ExpectedOutput: testID,
   647  		},
   648  		{
   649  			Name: "Returns error when creating the bundle instance auth fails",
   650  			InstanceAuthRepoFn: func() *automock.Repository {
   651  				instanceAuthRepo := &automock.Repository{}
   652  				instanceAuthRepo.On("Create", contextThatHasTenant(testTenant), modelExpectedInstanceAuth).Return(testError).Once()
   653  				return instanceAuthRepo
   654  			},
   655  			UIDSvcFn: func() *automock.UIDService {
   656  				svc := automock.UIDService{}
   657  				svc.On("Generate").Return(testID).Once()
   658  				return &svc
   659  			},
   660  			Input:          *modelCreateInput,
   661  			InputSchema:    nil,
   662  			ExpectedOutput: "",
   663  			ExpectedError:  testError,
   664  		},
   665  		{
   666  			Name: "Returns error when can't validate input params against schema",
   667  			Input: model.BundleInstanceAuthCreateInput{
   668  				InputParams: str.Ptr("{"),
   669  			},
   670  			InputSchema:    str.Ptr("{\"type\": \"string\"}"),
   671  			ExpectedOutput: "",
   672  			ExpectedError:  errors.New("while validating BundleInstanceAuth request input for Bundle"),
   673  		},
   674  	}
   675  
   676  	for _, testCase := range testCases {
   677  		t.Run(testCase.Name, func(t *testing.T) {
   678  			instanceAuthRepo := &automock.Repository{}
   679  			if testCase.InstanceAuthRepoFn != nil {
   680  				instanceAuthRepo = testCase.InstanceAuthRepoFn()
   681  			}
   682  			uidSvc := &automock.UIDService{}
   683  			if testCase.UIDSvcFn != nil {
   684  				uidSvc = testCase.UIDSvcFn()
   685  			}
   686  
   687  			svc := bundleinstanceauth.NewService(instanceAuthRepo, uidSvc)
   688  			svc.SetTimestampGen(func() time.Time { return testTime })
   689  
   690  			// WHEN
   691  			result, err := svc.CreateBundleInstanceAuth(ctx, testBundleID, testCase.Input, testCase.InputSchema)
   692  
   693  			// THEN
   694  			if testCase.ExpectedError != nil {
   695  				require.Error(t, err)
   696  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   697  			} else {
   698  				assert.NoError(t, err)
   699  			}
   700  			assert.Equal(t, testCase.ExpectedOutput, result)
   701  
   702  			mock.AssertExpectationsForObjects(t, instanceAuthRepo, uidSvc)
   703  		})
   704  
   705  		t.Run("Error when tenant not in context", func(t *testing.T) {
   706  			svc := bundleinstanceauth.NewService(nil, nil)
   707  
   708  			// WHEN
   709  			_, err := svc.CreateBundleInstanceAuth(context.TODO(), testBundleID, *modelCreateInput, nil)
   710  
   711  			// THEN
   712  			require.Error(t, err)
   713  			assert.Contains(t, err.Error(), "cannot read tenant from context")
   714  		})
   715  	}
   716  }
   717  
   718  func TestService_ListByApplicationID(t *testing.T) {
   719  	// GIVEN
   720  	testErr := errors.New("Test error")
   721  
   722  	tnt := testTenant
   723  	externalTnt := testExternalTenant
   724  
   725  	bundleInstanceAuths := []*model.BundleInstanceAuth{
   726  		fixSimpleModelBundleInstanceAuth(testBundleID),
   727  		fixSimpleModelBundleInstanceAuth(testBundleID),
   728  		fixSimpleModelBundleInstanceAuth(testBundleID),
   729  	}
   730  
   731  	ctx := context.TODO()
   732  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   733  
   734  	testCases := []struct {
   735  		Name               string
   736  		RepositoryFn       func() *automock.Repository
   737  		ExpectedResult     []*model.BundleInstanceAuth
   738  		ExpectedErrMessage string
   739  	}{
   740  		{
   741  			Name: "Success",
   742  			RepositoryFn: func() *automock.Repository {
   743  				repo := &automock.Repository{}
   744  				repo.On("ListByBundleID", ctx, tnt, testBundleID).Return(bundleInstanceAuths, nil).Once()
   745  				return repo
   746  			},
   747  			ExpectedResult:     bundleInstanceAuths,
   748  			ExpectedErrMessage: "",
   749  		},
   750  		{
   751  			Name: "Returns error when Bundle Instance Auth listing failed",
   752  			RepositoryFn: func() *automock.Repository {
   753  				repo := &automock.Repository{}
   754  				repo.On("ListByBundleID", ctx, tnt, testBundleID).Return(nil, testErr).Once()
   755  				return repo
   756  			},
   757  			ExpectedResult:     nil,
   758  			ExpectedErrMessage: testErr.Error(),
   759  		},
   760  	}
   761  
   762  	for _, testCase := range testCases {
   763  		t.Run(testCase.Name, func(t *testing.T) {
   764  			repo := testCase.RepositoryFn()
   765  
   766  			svc := bundleinstanceauth.NewService(repo, nil)
   767  
   768  			// WHEN
   769  			pia, err := svc.List(ctx, testBundleID)
   770  
   771  			// THEN
   772  			if testCase.ExpectedErrMessage == "" {
   773  				require.NoError(t, err)
   774  				assert.Equal(t, testCase.ExpectedResult, pia)
   775  			} else {
   776  				require.Error(t, err)
   777  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   778  			}
   779  
   780  			repo.AssertExpectations(t)
   781  		})
   782  	}
   783  
   784  	t.Run("Error when tenant not in context", func(t *testing.T) {
   785  		svc := bundleinstanceauth.NewService(nil, nil)
   786  		// WHEN
   787  		_, err := svc.List(context.TODO(), "")
   788  		// THEN
   789  		require.Error(t, err)
   790  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   791  	})
   792  }
   793  
   794  func TestService_ListByRuntimeID(t *testing.T) {
   795  	// GIVEN
   796  	testErr := errors.New("Test error")
   797  
   798  	tnt := testTenant
   799  	externalTnt := testExternalTenant
   800  
   801  	bundleInstanceAuths := []*model.BundleInstanceAuth{
   802  		fixSimpleModelBundleInstanceAuth(testBundleID),
   803  		fixSimpleModelBundleInstanceAuth(testBundleID),
   804  		fixSimpleModelBundleInstanceAuth(testBundleID),
   805  	}
   806  
   807  	ctx := context.TODO()
   808  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   809  
   810  	testCases := []struct {
   811  		Name               string
   812  		RepositoryFn       func() *automock.Repository
   813  		ExpectedResult     []*model.BundleInstanceAuth
   814  		ExpectedErrMessage string
   815  	}{
   816  		{
   817  			Name: "Success",
   818  			RepositoryFn: func() *automock.Repository {
   819  				repo := &automock.Repository{}
   820  				repo.On("ListByRuntimeID", ctx, tnt, testRuntimeID).Return(bundleInstanceAuths, nil).Once()
   821  				return repo
   822  			},
   823  			ExpectedResult:     bundleInstanceAuths,
   824  			ExpectedErrMessage: "",
   825  		},
   826  		{
   827  			Name: "Returns error when Bundle Instance Auth listing by runtime ID failed",
   828  			RepositoryFn: func() *automock.Repository {
   829  				repo := &automock.Repository{}
   830  				repo.On("ListByRuntimeID", ctx, tnt, testRuntimeID).Return(nil, testErr).Once()
   831  				return repo
   832  			},
   833  			ExpectedResult:     nil,
   834  			ExpectedErrMessage: testErr.Error(),
   835  		},
   836  	}
   837  
   838  	for _, testCase := range testCases {
   839  		t.Run(testCase.Name, func(t *testing.T) {
   840  			repo := testCase.RepositoryFn()
   841  
   842  			svc := bundleinstanceauth.NewService(repo, nil)
   843  
   844  			// WHEN
   845  			bundleInstanceAuth, err := svc.ListByRuntimeID(ctx, testRuntimeID)
   846  
   847  			// THEN
   848  			if testCase.ExpectedErrMessage == "" {
   849  				require.NoError(t, err)
   850  				assert.Equal(t, testCase.ExpectedResult, bundleInstanceAuth)
   851  			} else {
   852  				require.Error(t, err)
   853  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   854  			}
   855  
   856  			repo.AssertExpectations(t)
   857  		})
   858  	}
   859  
   860  	t.Run("Error when tenant not in context", func(t *testing.T) {
   861  		svc := bundleinstanceauth.NewService(nil, nil)
   862  
   863  		// WHEN
   864  		_, err := svc.ListByRuntimeID(context.TODO(), "")
   865  
   866  		// THEN
   867  		require.Error(t, err)
   868  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   869  	})
   870  }
   871  
   872  func TestService_Update(t *testing.T) {
   873  	// GIVEN
   874  	testErr := errors.New("Test error")
   875  
   876  	tnt := testTenant
   877  	externalTnt := testExternalTenant
   878  
   879  	bundleInstanceAuth := fixSimpleModelBundleInstanceAuth(testBundleID)
   880  
   881  	ctx := context.TODO()
   882  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   883  
   884  	testCases := []struct {
   885  		Name               string
   886  		RepositoryFn       func() *automock.Repository
   887  		ExpectedErrMessage string
   888  	}{
   889  		{
   890  			Name: "Success",
   891  			RepositoryFn: func() *automock.Repository {
   892  				repo := &automock.Repository{}
   893  				repo.On("Update", ctx, testTenant, bundleInstanceAuth).Return(nil).Once()
   894  				return repo
   895  			},
   896  			ExpectedErrMessage: "",
   897  		},
   898  		{
   899  			Name: "Returns error when bundle instance auth update failed",
   900  			RepositoryFn: func() *automock.Repository {
   901  				repo := &automock.Repository{}
   902  				repo.On("Update", ctx, testTenant, bundleInstanceAuth).Return(testErr).Once()
   903  				return repo
   904  			},
   905  			ExpectedErrMessage: testErr.Error(),
   906  		},
   907  	}
   908  
   909  	for _, testCase := range testCases {
   910  		t.Run(testCase.Name, func(t *testing.T) {
   911  			repo := testCase.RepositoryFn()
   912  
   913  			svc := bundleinstanceauth.NewService(repo, nil)
   914  
   915  			// WHEN
   916  			err := svc.Update(ctx, bundleInstanceAuth)
   917  
   918  			// THEN
   919  			if testCase.ExpectedErrMessage == "" {
   920  				require.NoError(t, err)
   921  			} else {
   922  				require.Error(t, err)
   923  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   924  			}
   925  
   926  			repo.AssertExpectations(t)
   927  		})
   928  	}
   929  }
   930  
   931  func TestService_RequestDeletion(t *testing.T) {
   932  	// GIVEN
   933  	tnt := testTenant
   934  	externalTnt := testExternalTenant
   935  
   936  	ctx := context.TODO()
   937  	ctx = tenant.SaveToContext(ctx, tnt, externalTnt)
   938  
   939  	id := "foo"
   940  	timestampNow := time.Now()
   941  	bndlInstanceAuth := fixSimpleModelBundleInstanceAuth(id)
   942  	//testErr := errors.New("test error")
   943  
   944  	testCases := []struct {
   945  		Name                      string
   946  		BundleDefaultInstanceAuth *model.Auth
   947  		InstanceAuthRepoFn        func() *automock.Repository
   948  
   949  		ExpectedResult bool
   950  		ExpectedError  error
   951  	}{
   952  		{
   953  			Name: "Success - No Bundle Default Instance Auth",
   954  			InstanceAuthRepoFn: func() *automock.Repository {
   955  				instanceAuthRepo := &automock.Repository{}
   956  				instanceAuthRepo.On("Update", contextThatHasTenant(tnt), tnt, mock.MatchedBy(func(in *model.BundleInstanceAuth) bool {
   957  					return in.ID == id && in.Status.Condition == model.BundleInstanceAuthStatusConditionUnused
   958  				})).Return(nil).Once()
   959  				return instanceAuthRepo
   960  			},
   961  			ExpectedResult: false,
   962  			ExpectedError:  nil,
   963  		},
   964  		{
   965  			Name:                      "Success - Bundle Default Instance Auth",
   966  			BundleDefaultInstanceAuth: fixModelAuth(),
   967  			InstanceAuthRepoFn: func() *automock.Repository {
   968  				instanceAuthRepo := &automock.Repository{}
   969  				instanceAuthRepo.On("Delete", contextThatHasTenant(tnt), tnt, id).Return(nil).Once()
   970  				return instanceAuthRepo
   971  			},
   972  			ExpectedResult: true,
   973  			ExpectedError:  nil,
   974  		},
   975  		{
   976  			Name: "Error - Update",
   977  			InstanceAuthRepoFn: func() *automock.Repository {
   978  				instanceAuthRepo := &automock.Repository{}
   979  				instanceAuthRepo.On("Update", contextThatHasTenant(tnt), tnt, mock.MatchedBy(func(in *model.BundleInstanceAuth) bool {
   980  					return in.ID == id && in.Status.Condition == model.BundleInstanceAuthStatusConditionUnused
   981  				})).Return(testError).Once()
   982  				return instanceAuthRepo
   983  			},
   984  			ExpectedError: testError,
   985  		},
   986  		{
   987  			Name:                      "Error - Delete",
   988  			BundleDefaultInstanceAuth: fixModelAuth(),
   989  			InstanceAuthRepoFn: func() *automock.Repository {
   990  				instanceAuthRepo := &automock.Repository{}
   991  				instanceAuthRepo.On("Delete", contextThatHasTenant(tnt), tnt, id).Return(testError).Once()
   992  				return instanceAuthRepo
   993  			},
   994  			ExpectedError: testError,
   995  		},
   996  	}
   997  
   998  	for _, testCase := range testCases {
   999  		t.Run(testCase.Name, func(t *testing.T) {
  1000  			instanceAuthRepo := testCase.InstanceAuthRepoFn()
  1001  
  1002  			svc := bundleinstanceauth.NewService(instanceAuthRepo, nil)
  1003  			svc.SetTimestampGen(func() time.Time {
  1004  				return timestampNow
  1005  			})
  1006  
  1007  			// WHEN
  1008  			res, err := svc.RequestDeletion(ctx, bndlInstanceAuth, testCase.BundleDefaultInstanceAuth)
  1009  
  1010  			// THEN
  1011  			if testCase.ExpectedError != nil {
  1012  				require.Error(t, err)
  1013  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1014  			} else {
  1015  				require.NoError(t, err)
  1016  				assert.Equal(t, testCase.ExpectedResult, res)
  1017  			}
  1018  
  1019  			instanceAuthRepo.AssertExpectations(t)
  1020  		})
  1021  	}
  1022  
  1023  	t.Run("Error - nil", func(t *testing.T) {
  1024  		// GIVEN
  1025  		expectedError := errors.New("BundleInstanceAuth is required to request its deletion")
  1026  
  1027  		// WHEN
  1028  		svc := bundleinstanceauth.NewService(nil, nil)
  1029  		_, err := svc.RequestDeletion(ctx, nil, nil)
  1030  
  1031  		// THEN
  1032  		require.Error(t, err)
  1033  		assert.Contains(t, err.Error(), expectedError.Error())
  1034  	})
  1035  }
  1036  
  1037  func contextThatHasTenant(expectedTenant string) interface{} {
  1038  	return mock.MatchedBy(func(actual context.Context) bool {
  1039  		actualTenant, err := tenant.LoadFromContext(actual)
  1040  		if err != nil {
  1041  			return false
  1042  		}
  1043  		return actualTenant == expectedTenant
  1044  	})
  1045  }