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

     1  package bundle_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/internal/domain/bundle"
    10  	"github.com/kyma-incubator/compass/components/director/internal/domain/bundle/automock"
    11  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    12  	"github.com/kyma-incubator/compass/components/director/internal/model"
    13  	"github.com/kyma-incubator/compass/components/director/pkg/pagination"
    14  	"github.com/pkg/errors"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/mock"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestService_Create(t *testing.T) {
    21  	// GIVEN
    22  	testErr := errors.New("Test error")
    23  
    24  	id := "foo"
    25  	applicationID := appID
    26  	name := "foo"
    27  
    28  	modelInput := model.BundleCreateInput{
    29  		Name:                           name,
    30  		Description:                    &desc,
    31  		InstanceAuthRequestInputSchema: fixBasicSchema(),
    32  		DefaultInstanceAuth:            &model.AuthInput{},
    33  		Documents: []*model.DocumentInput{
    34  			{Title: "foo", Description: "test", FetchRequest: &model.FetchRequestInput{URL: "doc.foo.bar"}},
    35  			{Title: "bar", Description: "test"},
    36  		},
    37  		APIDefinitions: []*model.APIDefinitionInput{
    38  			{
    39  				Name: "foo",
    40  			},
    41  			{
    42  				Name: "bar",
    43  			},
    44  		},
    45  		APISpecs: []*model.SpecInput{
    46  			{
    47  				FetchRequest: &model.FetchRequestInput{URL: "api.foo.bar"},
    48  			},
    49  			nil,
    50  		},
    51  		EventDefinitions: []*model.EventDefinitionInput{
    52  			{
    53  				Name: "foo",
    54  			},
    55  			{
    56  				Name: "bar",
    57  			},
    58  		},
    59  		EventSpecs: []*model.SpecInput{
    60  			{
    61  				FetchRequest: &model.FetchRequestInput{URL: "eventapi.foo.bar"},
    62  			},
    63  			nil,
    64  		},
    65  	}
    66  
    67  	modelBundleForApp := fixBasicModelBundle(id, name)
    68  	modelBundleForApp.ApplicationID = &appID
    69  
    70  	modelBundleForAppTemplateVersion := fixBasicModelBundle(id, name)
    71  	modelBundleForAppTemplateVersion.ApplicationTemplateVersionID = &appTemplateVersionID
    72  
    73  	ctx := context.TODO()
    74  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
    75  
    76  	testCases := []struct {
    77  		Name              string
    78  		RepositoryFn      func() *automock.BundleRepository
    79  		APIServiceFn      func() *automock.APIService
    80  		EventServiceFn    func() *automock.EventService
    81  		DocumentServiceFn func() *automock.DocumentService
    82  		UIDServiceFn      func() *automock.UIDService
    83  		Input             model.BundleCreateInput
    84  		ResourceType      resource.Type
    85  		ResourceID        string
    86  		ExpectedErr       error
    87  	}{
    88  		{
    89  			Name: "Success for Application",
    90  			RepositoryFn: func() *automock.BundleRepository {
    91  				repo := &automock.BundleRepository{}
    92  				repo.On("Create", ctx, tenantID, modelBundleForApp).Return(nil).Once()
    93  				return repo
    94  			},
    95  			UIDServiceFn: func() *automock.UIDService {
    96  				svc := &automock.UIDService{}
    97  				svc.On("Generate").Return(id)
    98  				return svc
    99  			},
   100  			APIServiceFn: func() *automock.APIService {
   101  				svc := &automock.APIService{}
   102  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[0], modelInput.APISpecs[0]).Return("", nil).Once()
   103  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[1], modelInput.APISpecs[1]).Return("", nil).Once()
   104  				return svc
   105  			},
   106  			EventServiceFn: func() *automock.EventService {
   107  				svc := &automock.EventService{}
   108  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.EventDefinitions[0], modelInput.EventSpecs[0]).Return("", nil).Once()
   109  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.EventDefinitions[1], modelInput.EventSpecs[1]).Return("", nil).Once()
   110  				return svc
   111  			},
   112  			DocumentServiceFn: func() *automock.DocumentService {
   113  				svc := &automock.DocumentService{}
   114  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.Documents[0]).Return("", nil).Once()
   115  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.Documents[1]).Return("", nil).Once()
   116  				return svc
   117  			},
   118  			Input:        modelInput,
   119  			ResourceType: resource.Application,
   120  			ResourceID:   applicationID,
   121  			ExpectedErr:  nil,
   122  		},
   123  		{
   124  			Name: "Success for Application Template Version",
   125  			RepositoryFn: func() *automock.BundleRepository {
   126  				repo := &automock.BundleRepository{}
   127  				repo.On("CreateGlobal", ctx, modelBundleForAppTemplateVersion).Return(nil).Once()
   128  				return repo
   129  			},
   130  			UIDServiceFn: func() *automock.UIDService {
   131  				svc := &automock.UIDService{}
   132  				svc.On("Generate").Return(id)
   133  				return svc
   134  			},
   135  			APIServiceFn: func() *automock.APIService {
   136  				svc := &automock.APIService{}
   137  				svc.On("CreateInBundle", ctx, resource.ApplicationTemplateVersion, appTemplateVersionID, id, *modelInput.APIDefinitions[0], modelInput.APISpecs[0]).Return("", nil).Once()
   138  				svc.On("CreateInBundle", ctx, resource.ApplicationTemplateVersion, appTemplateVersionID, id, *modelInput.APIDefinitions[1], modelInput.APISpecs[1]).Return("", nil).Once()
   139  				return svc
   140  			},
   141  			EventServiceFn: func() *automock.EventService {
   142  				svc := &automock.EventService{}
   143  				svc.On("CreateInBundle", ctx, resource.ApplicationTemplateVersion, appTemplateVersionID, id, *modelInput.EventDefinitions[0], modelInput.EventSpecs[0]).Return("", nil).Once()
   144  				svc.On("CreateInBundle", ctx, resource.ApplicationTemplateVersion, appTemplateVersionID, id, *modelInput.EventDefinitions[1], modelInput.EventSpecs[1]).Return("", nil).Once()
   145  				return svc
   146  			},
   147  			DocumentServiceFn: func() *automock.DocumentService {
   148  				svc := &automock.DocumentService{}
   149  				svc.On("CreateInBundle", ctx, resource.ApplicationTemplateVersion, appTemplateVersionID, id, *modelInput.Documents[0]).Return("", nil).Once()
   150  				svc.On("CreateInBundle", ctx, resource.ApplicationTemplateVersion, appTemplateVersionID, id, *modelInput.Documents[1]).Return("", nil).Once()
   151  				return svc
   152  			},
   153  			Input:        modelInput,
   154  			ResourceType: resource.ApplicationTemplateVersion,
   155  			ResourceID:   appTemplateVersionID,
   156  			ExpectedErr:  nil,
   157  		},
   158  		{
   159  			Name: "Error - Bundle creation for App",
   160  			RepositoryFn: func() *automock.BundleRepository {
   161  				repo := &automock.BundleRepository{}
   162  				repo.On("Create", ctx, tenantID, modelBundleForApp).Return(testErr).Once()
   163  				return repo
   164  			},
   165  			UIDServiceFn: func() *automock.UIDService {
   166  				svc := &automock.UIDService{}
   167  				svc.On("Generate").Return(id).Once()
   168  				return svc
   169  			},
   170  			APIServiceFn: func() *automock.APIService {
   171  				return &automock.APIService{}
   172  			},
   173  			EventServiceFn: func() *automock.EventService {
   174  				return &automock.EventService{}
   175  			},
   176  			DocumentServiceFn: func() *automock.DocumentService {
   177  				return &automock.DocumentService{}
   178  			},
   179  			Input:        modelInput,
   180  			ResourceType: resource.Application,
   181  			ResourceID:   applicationID,
   182  			ExpectedErr:  testErr,
   183  		},
   184  		{
   185  			Name: "Error - Bundle creation for App Template Version",
   186  			RepositoryFn: func() *automock.BundleRepository {
   187  				repo := &automock.BundleRepository{}
   188  				repo.On("CreateGlobal", ctx, modelBundleForAppTemplateVersion).Return(testErr).Once()
   189  				return repo
   190  			},
   191  			UIDServiceFn: func() *automock.UIDService {
   192  				svc := &automock.UIDService{}
   193  				svc.On("Generate").Return(id).Once()
   194  				return svc
   195  			},
   196  			APIServiceFn: func() *automock.APIService {
   197  				return &automock.APIService{}
   198  			},
   199  			EventServiceFn: func() *automock.EventService {
   200  				return &automock.EventService{}
   201  			},
   202  			DocumentServiceFn: func() *automock.DocumentService {
   203  				return &automock.DocumentService{}
   204  			},
   205  			Input:        modelInput,
   206  			ResourceType: resource.ApplicationTemplateVersion,
   207  			ResourceID:   appTemplateVersionID,
   208  			ExpectedErr:  nil,
   209  		},
   210  		{
   211  			Name: "Error - API creation",
   212  			RepositoryFn: func() *automock.BundleRepository {
   213  				repo := &automock.BundleRepository{}
   214  				repo.On("Create", ctx, tenantID, modelBundleForApp).Return(nil).Once()
   215  				return repo
   216  			},
   217  			UIDServiceFn: func() *automock.UIDService {
   218  				svc := &automock.UIDService{}
   219  				svc.On("Generate").Return(id)
   220  				return svc
   221  			},
   222  			APIServiceFn: func() *automock.APIService {
   223  				svc := &automock.APIService{}
   224  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[0], modelInput.APISpecs[0]).Return("", testErr).Once()
   225  				return svc
   226  			},
   227  			EventServiceFn: func() *automock.EventService {
   228  				svc := &automock.EventService{}
   229  				return svc
   230  			},
   231  			DocumentServiceFn: func() *automock.DocumentService {
   232  				svc := &automock.DocumentService{}
   233  				return svc
   234  			},
   235  			Input:        modelInput,
   236  			ResourceType: resource.Application,
   237  			ResourceID:   applicationID,
   238  			ExpectedErr:  testErr,
   239  		},
   240  		{
   241  			Name: "Error - Event creation",
   242  			RepositoryFn: func() *automock.BundleRepository {
   243  				repo := &automock.BundleRepository{}
   244  				repo.On("Create", ctx, tenantID, modelBundleForApp).Return(nil).Once()
   245  				return repo
   246  			},
   247  			UIDServiceFn: func() *automock.UIDService {
   248  				svc := &automock.UIDService{}
   249  				svc.On("Generate").Return(id)
   250  				return svc
   251  			},
   252  			APIServiceFn: func() *automock.APIService {
   253  				svc := &automock.APIService{}
   254  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[0], modelInput.APISpecs[0]).Return("", nil).Once()
   255  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[1], modelInput.APISpecs[1]).Return("", nil).Once()
   256  				return svc
   257  			},
   258  			EventServiceFn: func() *automock.EventService {
   259  				svc := &automock.EventService{}
   260  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.EventDefinitions[0], modelInput.EventSpecs[0]).Return("", testErr).Once()
   261  				return svc
   262  			},
   263  			DocumentServiceFn: func() *automock.DocumentService {
   264  				repo := &automock.DocumentService{}
   265  				return repo
   266  			},
   267  			Input:        modelInput,
   268  			ResourceType: resource.Application,
   269  			ResourceID:   applicationID,
   270  			ExpectedErr:  testErr,
   271  		},
   272  		{
   273  			Name: "Error - Document creation",
   274  			RepositoryFn: func() *automock.BundleRepository {
   275  				repo := &automock.BundleRepository{}
   276  				repo.On("Create", ctx, tenantID, modelBundleForApp).Return(nil).Once()
   277  				return repo
   278  			},
   279  			UIDServiceFn: func() *automock.UIDService {
   280  				svc := &automock.UIDService{}
   281  				svc.On("Generate").Return(id)
   282  				return svc
   283  			},
   284  			APIServiceFn: func() *automock.APIService {
   285  				svc := &automock.APIService{}
   286  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[0], modelInput.APISpecs[0]).Return("", nil).Once()
   287  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.APIDefinitions[1], modelInput.APISpecs[1]).Return("", nil).Once()
   288  				return svc
   289  			},
   290  			EventServiceFn: func() *automock.EventService {
   291  				svc := &automock.EventService{}
   292  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.EventDefinitions[0], modelInput.EventSpecs[0]).Return("", nil).Once()
   293  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.EventDefinitions[1], modelInput.EventSpecs[1]).Return("", nil).Once()
   294  				return svc
   295  			},
   296  			DocumentServiceFn: func() *automock.DocumentService {
   297  				svc := &automock.DocumentService{}
   298  				svc.On("CreateInBundle", ctx, resource.Application, appID, id, *modelInput.Documents[0]).Return("", testErr).Once()
   299  				return svc
   300  			},
   301  			Input:        modelInput,
   302  			ResourceType: resource.Application,
   303  			ResourceID:   applicationID,
   304  			ExpectedErr:  testErr,
   305  		},
   306  	}
   307  
   308  	for _, testCase := range testCases {
   309  		t.Run(testCase.Name, func(t *testing.T) {
   310  			// GIVEN
   311  			repo := testCase.RepositoryFn()
   312  			uidService := testCase.UIDServiceFn()
   313  
   314  			apiSvc := testCase.APIServiceFn()
   315  			eventSvc := testCase.EventServiceFn()
   316  			documentSvc := testCase.DocumentServiceFn()
   317  			svc := bundle.NewService(repo, apiSvc, eventSvc, documentSvc, uidService)
   318  
   319  			// WHEN
   320  			result, err := svc.Create(ctx, testCase.ResourceType, testCase.ResourceID, testCase.Input)
   321  
   322  			// THEN
   323  			if testCase.ExpectedErr != nil {
   324  				require.Error(t, err)
   325  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
   326  			} else {
   327  				assert.IsType(t, "string", result)
   328  			}
   329  
   330  			mock.AssertExpectationsForObjects(t, repo, apiSvc, eventSvc, documentSvc, uidService)
   331  		})
   332  	}
   333  	t.Run("Error when tenant not in context", func(t *testing.T) {
   334  		svc := bundle.NewService(nil, nil, nil, nil, fixUIDService())
   335  		// WHEN
   336  		_, err := svc.Create(context.TODO(), resource.Application, appID, model.BundleCreateInput{})
   337  		// THEN
   338  		require.Error(t, err)
   339  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   340  	})
   341  }
   342  
   343  func TestService_Update(t *testing.T) {
   344  	// GIVEN
   345  	testErr := errors.New("Test error")
   346  
   347  	id := "foo"
   348  	name := "bar"
   349  
   350  	modelInput := model.BundleUpdateInput{
   351  		Name:                           name,
   352  		Description:                    &desc,
   353  		InstanceAuthRequestInputSchema: fixBasicSchema(),
   354  		DefaultInstanceAuth:            &model.AuthInput{},
   355  	}
   356  
   357  	inputBundleModel := mock.MatchedBy(func(bndl *model.Bundle) bool {
   358  		return bndl.Name == modelInput.Name
   359  	})
   360  
   361  	bundleModelForApp := fixBasicModelBundle(id, name)
   362  	bundleModelForApp.ApplicationID = &appID
   363  
   364  	bundleModelForAppTemplateVersion := fixBasicModelBundle(id, name)
   365  	bundleModelForApp.ApplicationTemplateVersionID = &appTemplateVersionID
   366  
   367  	ctx := context.TODO()
   368  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
   369  
   370  	testCases := []struct {
   371  		Name         string
   372  		RepositoryFn func() *automock.BundleRepository
   373  		Input        model.BundleUpdateInput
   374  		InputID      string
   375  		ResourceType resource.Type
   376  		ExpectedErr  error
   377  	}{
   378  		{
   379  			Name: "Success for App",
   380  			RepositoryFn: func() *automock.BundleRepository {
   381  				repo := &automock.BundleRepository{}
   382  				repo.On("GetByID", ctx, tenantID, id).Return(bundleModelForApp, nil).Once()
   383  				repo.On("Update", ctx, tenantID, inputBundleModel).Return(nil).Once()
   384  				return repo
   385  			},
   386  			InputID:      "foo",
   387  			Input:        modelInput,
   388  			ResourceType: resource.Application,
   389  			ExpectedErr:  nil,
   390  		},
   391  		{
   392  			Name: "Success for App Template Version",
   393  			RepositoryFn: func() *automock.BundleRepository {
   394  				repo := &automock.BundleRepository{}
   395  				repo.On("GetByIDGlobal", ctx, id).Return(bundleModelForAppTemplateVersion, nil).Once()
   396  				repo.On("UpdateGlobal", ctx, inputBundleModel).Return(nil).Once()
   397  				return repo
   398  			},
   399  			InputID:      "foo",
   400  			Input:        modelInput,
   401  			ResourceType: resource.ApplicationTemplateVersion,
   402  			ExpectedErr:  nil,
   403  		},
   404  		{
   405  			Name: "Update Error",
   406  			RepositoryFn: func() *automock.BundleRepository {
   407  				repo := &automock.BundleRepository{}
   408  				repo.On("GetByID", ctx, tenantID, "foo").Return(bundleModelForApp, nil).Once()
   409  				repo.On("Update", ctx, tenantID, inputBundleModel).Return(testErr).Once()
   410  				return repo
   411  			},
   412  			InputID:      "foo",
   413  			Input:        modelInput,
   414  			ResourceType: resource.Application,
   415  			ExpectedErr:  testErr,
   416  		},
   417  		{
   418  			Name: "Update Error for Application Template Version",
   419  			RepositoryFn: func() *automock.BundleRepository {
   420  				repo := &automock.BundleRepository{}
   421  				repo.On("GetByIDGlobal", ctx, "foo").Return(bundleModelForApp, nil).Once()
   422  				repo.On("UpdateGlobal", ctx, inputBundleModel).Return(testErr).Once()
   423  				return repo
   424  			},
   425  			InputID:      "foo",
   426  			Input:        modelInput,
   427  			ResourceType: resource.ApplicationTemplateVersion,
   428  			ExpectedErr:  testErr,
   429  		},
   430  		{
   431  			Name: "Get Error",
   432  			RepositoryFn: func() *automock.BundleRepository {
   433  				repo := &automock.BundleRepository{}
   434  				repo.On("GetByID", ctx, tenantID, "foo").Return(nil, testErr).Once()
   435  				return repo
   436  			},
   437  			InputID:      "foo",
   438  			Input:        modelInput,
   439  			ResourceType: resource.Application,
   440  			ExpectedErr:  testErr,
   441  		},
   442  		{
   443  			Name: "Get Error for Application Template Version",
   444  			RepositoryFn: func() *automock.BundleRepository {
   445  				repo := &automock.BundleRepository{}
   446  				repo.On("GetByIDGlobal", ctx, "foo").Return(nil, testErr).Once()
   447  				return repo
   448  			},
   449  			InputID:      "foo",
   450  			Input:        modelInput,
   451  			ResourceType: resource.ApplicationTemplateVersion,
   452  			ExpectedErr:  testErr,
   453  		},
   454  	}
   455  
   456  	for _, testCase := range testCases {
   457  		t.Run(testCase.Name, func(t *testing.T) {
   458  			// GIVEN
   459  			repo := testCase.RepositoryFn()
   460  
   461  			svc := bundle.NewService(repo, nil, nil, nil, nil)
   462  
   463  			// WHEN
   464  			err := svc.Update(ctx, testCase.ResourceType, testCase.InputID, testCase.Input)
   465  
   466  			// THEN
   467  			if testCase.ExpectedErr == nil {
   468  				require.NoError(t, err)
   469  			} else {
   470  				require.Error(t, err)
   471  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
   472  			}
   473  
   474  			repo.AssertExpectations(t)
   475  		})
   476  	}
   477  	t.Run("Error when tenant not in context", func(t *testing.T) {
   478  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   479  		// WHEN
   480  		err := svc.Update(context.TODO(), resource.Application, "", model.BundleUpdateInput{})
   481  		// THEN
   482  		require.Error(t, err)
   483  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   484  	})
   485  }
   486  
   487  func TestService_Delete(t *testing.T) {
   488  	// GIVEN
   489  	testErr := errors.New("Test error")
   490  
   491  	id := "foo"
   492  
   493  	ctx := context.TODO()
   494  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
   495  
   496  	testCases := []struct {
   497  		Name         string
   498  		RepositoryFn func() *automock.BundleRepository
   499  		Input        model.BundleCreateInput
   500  		InputID      string
   501  		ResourceType resource.Type
   502  		ExpectedErr  error
   503  	}{
   504  		{
   505  			Name: "Success for Application",
   506  			RepositoryFn: func() *automock.BundleRepository {
   507  				repo := &automock.BundleRepository{}
   508  				repo.On("Delete", ctx, tenantID, id).Return(nil).Once()
   509  				return repo
   510  			},
   511  			InputID:      id,
   512  			ResourceType: resource.Application,
   513  			ExpectedErr:  nil,
   514  		},
   515  		{
   516  			Name: "Success for Application Template Version",
   517  			RepositoryFn: func() *automock.BundleRepository {
   518  				repo := &automock.BundleRepository{}
   519  				repo.On("DeleteGlobal", ctx, id).Return(nil).Once()
   520  				return repo
   521  			},
   522  			InputID:      id,
   523  			ResourceType: resource.ApplicationTemplateVersion,
   524  			ExpectedErr:  nil,
   525  		},
   526  		{
   527  			Name: "Delete Error for Application",
   528  			RepositoryFn: func() *automock.BundleRepository {
   529  				repo := &automock.BundleRepository{}
   530  				repo.On("Delete", ctx, tenantID, id).Return(testErr).Once()
   531  				return repo
   532  			},
   533  			InputID:      id,
   534  			ResourceType: resource.Application,
   535  			ExpectedErr:  testErr,
   536  		},
   537  		{
   538  			Name: "Delete Error for Application Template Version",
   539  			RepositoryFn: func() *automock.BundleRepository {
   540  				repo := &automock.BundleRepository{}
   541  				repo.On("DeleteGlobal", ctx, id).Return(testErr).Once()
   542  				return repo
   543  			},
   544  			InputID:      id,
   545  			ResourceType: resource.ApplicationTemplateVersion,
   546  			ExpectedErr:  testErr,
   547  		},
   548  	}
   549  
   550  	for _, testCase := range testCases {
   551  		t.Run(testCase.Name, func(t *testing.T) {
   552  			// GIVEN
   553  			repo := testCase.RepositoryFn()
   554  
   555  			svc := bundle.NewService(repo, nil, nil, nil, nil)
   556  
   557  			// WHEN
   558  			err := svc.Delete(ctx, testCase.ResourceType, testCase.InputID)
   559  
   560  			// THEN
   561  			if testCase.ExpectedErr == nil {
   562  				require.NoError(t, err)
   563  			} else {
   564  				require.Error(t, err)
   565  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
   566  			}
   567  
   568  			repo.AssertExpectations(t)
   569  		})
   570  	}
   571  	t.Run("Error when tenant not in context", func(t *testing.T) {
   572  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   573  		// WHEN
   574  		err := svc.Delete(context.TODO(), resource.Application, "")
   575  		// THEN
   576  		require.Error(t, err)
   577  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   578  	})
   579  }
   580  
   581  func TestService_Exist(t *testing.T) {
   582  	// GIVEN
   583  	testErr := errors.New("Test error")
   584  	ctx := tenant.SaveToContext(context.TODO(), tenantID, externalTenantID)
   585  	id := "foo"
   586  
   587  	testCases := []struct {
   588  		Name           string
   589  		RepoFn         func() *automock.BundleRepository
   590  		ExpectedError  error
   591  		ExpectedOutput bool
   592  	}{
   593  		{
   594  			Name: "Success",
   595  			RepoFn: func() *automock.BundleRepository {
   596  				bndlRepo := &automock.BundleRepository{}
   597  				bndlRepo.On("Exists", ctx, tenantID, id).Return(true, nil).Once()
   598  				return bndlRepo
   599  			},
   600  			ExpectedOutput: true,
   601  		},
   602  		{
   603  			Name: "Error when getting Bundle",
   604  			RepoFn: func() *automock.BundleRepository {
   605  				bndlRepo := &automock.BundleRepository{}
   606  				bndlRepo.On("Exists", ctx, tenantID, id).Return(false, testErr).Once()
   607  				return bndlRepo
   608  			},
   609  			ExpectedError:  testErr,
   610  			ExpectedOutput: false,
   611  		},
   612  	}
   613  
   614  	for _, testCase := range testCases {
   615  		t.Run(testCase.Name, func(t *testing.T) {
   616  			bndlRepo := testCase.RepoFn()
   617  			svc := bundle.NewService(bndlRepo, nil, nil, nil, nil)
   618  
   619  			// WHEN
   620  			result, err := svc.Exist(ctx, id)
   621  
   622  			// THEN
   623  			if testCase.ExpectedError != nil {
   624  				require.Error(t, err)
   625  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   626  			} else {
   627  				assert.NoError(t, err)
   628  			}
   629  			assert.Equal(t, testCase.ExpectedOutput, result)
   630  
   631  			bndlRepo.AssertExpectations(t)
   632  		})
   633  	}
   634  
   635  	t.Run("Error when tenant not in context", func(t *testing.T) {
   636  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   637  		// WHEN
   638  		_, err := svc.Exist(context.TODO(), "")
   639  		// THEN
   640  		require.Error(t, err)
   641  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   642  	})
   643  }
   644  
   645  func TestService_Get(t *testing.T) {
   646  	// GIVEN
   647  	testErr := errors.New("Test error")
   648  
   649  	id := "foo"
   650  	name := "foo"
   651  	desc := "bar"
   652  
   653  	bndl := fixBundleModel(name, desc)
   654  
   655  	ctx := context.TODO()
   656  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
   657  
   658  	testCases := []struct {
   659  		Name               string
   660  		RepositoryFn       func() *automock.BundleRepository
   661  		Input              model.BundleCreateInput
   662  		InputID            string
   663  		ExpectedBundle     *model.Bundle
   664  		ExpectedErrMessage string
   665  	}{
   666  		{
   667  			Name: "Success",
   668  			RepositoryFn: func() *automock.BundleRepository {
   669  				repo := &automock.BundleRepository{}
   670  				repo.On("GetByID", ctx, tenantID, id).Return(bndl, nil).Once()
   671  				return repo
   672  			},
   673  			InputID:            id,
   674  			ExpectedBundle:     bndl,
   675  			ExpectedErrMessage: "",
   676  		},
   677  		{
   678  			Name: "Returns error when Bundle retrieval failed",
   679  			RepositoryFn: func() *automock.BundleRepository {
   680  				repo := &automock.BundleRepository{}
   681  				repo.On("GetByID", ctx, tenantID, id).Return(nil, testErr).Once()
   682  				return repo
   683  			},
   684  			InputID:            id,
   685  			ExpectedBundle:     bndl,
   686  			ExpectedErrMessage: testErr.Error(),
   687  		},
   688  	}
   689  
   690  	for _, testCase := range testCases {
   691  		t.Run(testCase.Name, func(t *testing.T) {
   692  			repo := testCase.RepositoryFn()
   693  			svc := bundle.NewService(repo, nil, nil, nil, nil)
   694  
   695  			// WHEN
   696  			bndl, err := svc.Get(ctx, testCase.InputID)
   697  
   698  			// THEN
   699  			if testCase.ExpectedErrMessage == "" {
   700  				require.NoError(t, err)
   701  				assert.Equal(t, testCase.ExpectedBundle, bndl)
   702  			} else {
   703  				require.Error(t, err)
   704  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   705  			}
   706  
   707  			repo.AssertExpectations(t)
   708  		})
   709  	}
   710  	t.Run("Error when tenant not in context", func(t *testing.T) {
   711  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   712  		// WHEN
   713  		_, err := svc.Get(context.TODO(), "")
   714  		// THEN
   715  		require.Error(t, err)
   716  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   717  	})
   718  }
   719  
   720  func TestService_GetForApplication(t *testing.T) {
   721  	// GIVEN
   722  	testErr := errors.New("Test error")
   723  
   724  	id := "foo"
   725  	appID := "bar"
   726  	name := "foo"
   727  	desc := "bar"
   728  
   729  	bndl := fixBundleModel(name, desc)
   730  
   731  	ctx := context.TODO()
   732  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
   733  
   734  	testCases := []struct {
   735  		Name               string
   736  		RepositoryFn       func() *automock.BundleRepository
   737  		Input              model.BundleCreateInput
   738  		InputID            string
   739  		ApplicationID      string
   740  		ExpectedBundle     *model.Bundle
   741  		ExpectedErrMessage string
   742  	}{
   743  		{
   744  			Name: "Success",
   745  			RepositoryFn: func() *automock.BundleRepository {
   746  				repo := &automock.BundleRepository{}
   747  				repo.On("GetForApplication", ctx, tenantID, id, appID).Return(bndl, nil).Once()
   748  				return repo
   749  			},
   750  			InputID:            id,
   751  			ApplicationID:      appID,
   752  			ExpectedBundle:     bndl,
   753  			ExpectedErrMessage: "",
   754  		},
   755  		{
   756  			Name: "Returns error when Bundle retrieval failed",
   757  			RepositoryFn: func() *automock.BundleRepository {
   758  				repo := &automock.BundleRepository{}
   759  				repo.On("GetForApplication", ctx, tenantID, id, appID).Return(nil, testErr).Once()
   760  				return repo
   761  			},
   762  			InputID:            id,
   763  			ApplicationID:      appID,
   764  			ExpectedBundle:     nil,
   765  			ExpectedErrMessage: testErr.Error(),
   766  		},
   767  	}
   768  
   769  	for _, testCase := range testCases {
   770  		t.Run(testCase.Name, func(t *testing.T) {
   771  			repo := testCase.RepositoryFn()
   772  			svc := bundle.NewService(repo, nil, nil, nil, nil)
   773  
   774  			// WHEN
   775  			document, err := svc.GetForApplication(ctx, testCase.InputID, testCase.ApplicationID)
   776  
   777  			// THEN
   778  			if testCase.ExpectedErrMessage == "" {
   779  				require.NoError(t, err)
   780  				assert.Equal(t, testCase.ExpectedBundle, document)
   781  			} else {
   782  				require.Error(t, err)
   783  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   784  			}
   785  
   786  			repo.AssertExpectations(t)
   787  		})
   788  	}
   789  	t.Run("Error when tenant not in context", func(t *testing.T) {
   790  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   791  		// WHEN
   792  		_, err := svc.GetForApplication(context.TODO(), "", "")
   793  		// THEN
   794  		require.Error(t, err)
   795  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   796  	})
   797  }
   798  
   799  func TestService_ListByApplicationIDNoPaging(t *testing.T) {
   800  	// GIVEN
   801  	testErr := errors.New("Test error")
   802  
   803  	name := "foo"
   804  	desc := "bar"
   805  
   806  	bundles := []*model.Bundle{
   807  		fixBundleModel(name, desc),
   808  		fixBundleModel(name, desc),
   809  		fixBundleModel(name, desc),
   810  	}
   811  
   812  	ctx := context.TODO()
   813  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
   814  
   815  	testCases := []struct {
   816  		Name               string
   817  		RepositoryFn       func() *automock.BundleRepository
   818  		ExpectedResult     []*model.Bundle
   819  		ExpectedErrMessage string
   820  	}{
   821  		{
   822  			Name: "Success",
   823  			RepositoryFn: func() *automock.BundleRepository {
   824  				repo := &automock.BundleRepository{}
   825  				repo.On("ListByResourceIDNoPaging", ctx, tenantID, appID, resource.Application).Return(bundles, nil).Once()
   826  				return repo
   827  			},
   828  			ExpectedResult:     bundles,
   829  			ExpectedErrMessage: "",
   830  		},
   831  		{
   832  			Name: "Returns error when Bundle listing failed",
   833  			RepositoryFn: func() *automock.BundleRepository {
   834  				repo := &automock.BundleRepository{}
   835  				repo.On("ListByResourceIDNoPaging", ctx, tenantID, appID, resource.Application).Return(nil, testErr).Once()
   836  				return repo
   837  			},
   838  			ExpectedResult:     nil,
   839  			ExpectedErrMessage: testErr.Error(),
   840  		},
   841  	}
   842  
   843  	for _, testCase := range testCases {
   844  		t.Run(testCase.Name, func(t *testing.T) {
   845  			repo := testCase.RepositoryFn()
   846  
   847  			svc := bundle.NewService(repo, nil, nil, nil, nil)
   848  
   849  			// WHEN
   850  			docs, err := svc.ListByApplicationIDNoPaging(ctx, appID)
   851  
   852  			// THEN
   853  			if testCase.ExpectedErrMessage == "" {
   854  				require.NoError(t, err)
   855  				assert.Equal(t, testCase.ExpectedResult, docs)
   856  			} else {
   857  				require.Error(t, err)
   858  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   859  			}
   860  
   861  			repo.AssertExpectations(t)
   862  		})
   863  	}
   864  	t.Run("Error when tenant not in context", func(t *testing.T) {
   865  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   866  		// WHEN
   867  		_, err := svc.ListByApplicationIDNoPaging(context.TODO(), "")
   868  		// THEN
   869  		require.Error(t, err)
   870  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   871  	})
   872  }
   873  
   874  func TestService_ListByApplicationTemplateVersionIDNoPaging(t *testing.T) {
   875  	// GIVEN
   876  	testErr := errors.New("Test error")
   877  
   878  	name := "foo"
   879  
   880  	bundles := []*model.Bundle{
   881  		fixBundleModel(name, desc),
   882  		fixBundleModel(name, desc),
   883  	}
   884  
   885  	ctx := context.TODO()
   886  
   887  	testCases := []struct {
   888  		Name               string
   889  		RepositoryFn       func() *automock.BundleRepository
   890  		ExpectedResult     []*model.Bundle
   891  		ExpectedErrMessage string
   892  	}{
   893  		{
   894  			Name: "Success",
   895  			RepositoryFn: func() *automock.BundleRepository {
   896  				repo := &automock.BundleRepository{}
   897  				repo.On("ListByResourceIDNoPaging", ctx, "", appTemplateVersionID, resource.ApplicationTemplateVersion).Return(bundles, nil).Once()
   898  				return repo
   899  			},
   900  			ExpectedResult:     bundles,
   901  			ExpectedErrMessage: "",
   902  		},
   903  		{
   904  			Name: "Returns error when Bundle listing failed",
   905  			RepositoryFn: func() *automock.BundleRepository {
   906  				repo := &automock.BundleRepository{}
   907  				repo.On("ListByResourceIDNoPaging", ctx, "", appTemplateVersionID, resource.ApplicationTemplateVersion).Return(nil, testErr).Once()
   908  				return repo
   909  			},
   910  			ExpectedResult:     nil,
   911  			ExpectedErrMessage: testErr.Error(),
   912  		},
   913  	}
   914  
   915  	for _, testCase := range testCases {
   916  		t.Run(testCase.Name, func(t *testing.T) {
   917  			repo := testCase.RepositoryFn()
   918  
   919  			svc := bundle.NewService(repo, nil, nil, nil, nil)
   920  
   921  			// WHEN
   922  			docs, err := svc.ListByApplicationTemplateVersionIDNoPaging(ctx, appTemplateVersionID)
   923  
   924  			// THEN
   925  			if testCase.ExpectedErrMessage == "" {
   926  				require.NoError(t, err)
   927  				assert.Equal(t, testCase.ExpectedResult, docs)
   928  			} else {
   929  				require.Error(t, err)
   930  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   931  			}
   932  
   933  			repo.AssertExpectations(t)
   934  		})
   935  	}
   936  	t.Run("Error when tenant not in context", func(t *testing.T) {
   937  		svc := bundle.NewService(nil, nil, nil, nil, nil)
   938  		// WHEN
   939  		_, err := svc.ListByApplicationIDNoPaging(context.TODO(), "")
   940  		// THEN
   941  		require.Error(t, err)
   942  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   943  	})
   944  }
   945  
   946  func TestService_ListByApplicationIDs(t *testing.T) {
   947  	// GIVEN
   948  	testErr := errors.New("Test error")
   949  
   950  	firstAppID := "bar"
   951  	secondAppID := "bar2"
   952  	name := "foo"
   953  	desc := "bar"
   954  	appIDs := []string{firstAppID, secondAppID}
   955  
   956  	bundleFirstApp := fixBundleModel(name, desc)
   957  	bundleFirstApp.ApplicationID = &firstAppID
   958  	bundleSecondApp := fixBundleModel(name, desc)
   959  	bundleSecondApp.ApplicationID = &secondAppID
   960  
   961  	bundlesFirstApp := []*model.Bundle{bundleFirstApp}
   962  	bundlesSecondApp := []*model.Bundle{bundleSecondApp}
   963  
   964  	bundlePageFirstApp := &model.BundlePage{
   965  		Data:       bundlesFirstApp,
   966  		TotalCount: len(bundlesFirstApp),
   967  		PageInfo: &pagination.Page{
   968  			HasNextPage: false,
   969  			EndCursor:   "end",
   970  			StartCursor: "start",
   971  		},
   972  	}
   973  	bundlePageSecondApp := &model.BundlePage{
   974  		Data:       bundlesSecondApp,
   975  		TotalCount: len(bundlesSecondApp),
   976  		PageInfo: &pagination.Page{
   977  			HasNextPage: false,
   978  			EndCursor:   "end",
   979  			StartCursor: "start",
   980  		},
   981  	}
   982  
   983  	bundlePages := []*model.BundlePage{bundlePageFirstApp, bundlePageSecondApp}
   984  
   985  	after := "test"
   986  
   987  	ctx := context.TODO()
   988  	ctx = tenant.SaveToContext(ctx, tenantID, externalTenantID)
   989  
   990  	testCases := []struct {
   991  		Name               string
   992  		PageSize           int
   993  		RepositoryFn       func() *automock.BundleRepository
   994  		ExpectedResult     []*model.BundlePage
   995  		ExpectedErrMessage string
   996  	}{
   997  		{
   998  			Name: "Success",
   999  			RepositoryFn: func() *automock.BundleRepository {
  1000  				repo := &automock.BundleRepository{}
  1001  				repo.On("ListByApplicationIDs", ctx, tenantID, appIDs, 2, after).Return(bundlePages, nil).Once()
  1002  				return repo
  1003  			},
  1004  			PageSize:           2,
  1005  			ExpectedResult:     bundlePages,
  1006  			ExpectedErrMessage: "",
  1007  		},
  1008  		{
  1009  			Name: "Return error when page size is less than 1",
  1010  			RepositoryFn: func() *automock.BundleRepository {
  1011  				repo := &automock.BundleRepository{}
  1012  				return repo
  1013  			},
  1014  			PageSize:           0,
  1015  			ExpectedResult:     bundlePages,
  1016  			ExpectedErrMessage: "page size must be between 1 and 200",
  1017  		},
  1018  		{
  1019  			Name: "Return error when page size is bigger than 200",
  1020  			RepositoryFn: func() *automock.BundleRepository {
  1021  				repo := &automock.BundleRepository{}
  1022  				return repo
  1023  			},
  1024  			PageSize:           201,
  1025  			ExpectedResult:     bundlePages,
  1026  			ExpectedErrMessage: "page size must be between 1 and 200",
  1027  		},
  1028  		{
  1029  			Name: "Returns error when Bundle listing failed",
  1030  			RepositoryFn: func() *automock.BundleRepository {
  1031  				repo := &automock.BundleRepository{}
  1032  				repo.On("ListByApplicationIDs", ctx, tenantID, appIDs, 2, after).Return(nil, testErr).Once()
  1033  				return repo
  1034  			},
  1035  			PageSize:           2,
  1036  			ExpectedResult:     nil,
  1037  			ExpectedErrMessage: testErr.Error(),
  1038  		},
  1039  	}
  1040  
  1041  	for _, testCase := range testCases {
  1042  		t.Run(testCase.Name, func(t *testing.T) {
  1043  			repo := testCase.RepositoryFn()
  1044  
  1045  			svc := bundle.NewService(repo, nil, nil, nil, nil)
  1046  
  1047  			// WHEN
  1048  			bndls, err := svc.ListByApplicationIDs(ctx, appIDs, testCase.PageSize, after)
  1049  
  1050  			// then
  1051  			if testCase.ExpectedErrMessage == "" {
  1052  				require.NoError(t, err)
  1053  				assert.Equal(t, testCase.ExpectedResult, bndls)
  1054  			} else {
  1055  				require.Error(t, err)
  1056  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  1057  			}
  1058  
  1059  			repo.AssertExpectations(t)
  1060  		})
  1061  	}
  1062  	t.Run("Error when tenant not in context", func(t *testing.T) {
  1063  		svc := bundle.NewService(nil, nil, nil, nil, nil)
  1064  		// WHEN
  1065  		_, err := svc.ListByApplicationIDs(context.TODO(), nil, 5, "")
  1066  		// THEN
  1067  		require.Error(t, err)
  1068  		assert.Contains(t, err.Error(), "cannot read tenant from context")
  1069  	})
  1070  }
  1071  
  1072  func fixUIDService() *automock.UIDService {
  1073  	svc := &automock.UIDService{}
  1074  	svc.On("Generate").Return(appID)
  1075  	return svc
  1076  }