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

     1  package tenant_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/pkg/errors"
     9  
    10  	"github.com/kyma-incubator/compass/components/director/pkg/pagination"
    11  
    12  	tnt "github.com/kyma-incubator/compass/components/director/pkg/tenant"
    13  
    14  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    15  
    16  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    17  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    18  	"github.com/stretchr/testify/mock"
    19  
    20  	"github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest"
    21  
    22  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    23  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant/automock"
    24  	"github.com/kyma-incubator/compass/components/director/internal/model"
    25  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    26  	persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestResolver_Tenants(t *testing.T) {
    32  	// GIVEN
    33  	ctx := context.TODO()
    34  	txGen := txtest.NewTransactionContextGenerator(testError)
    35  
    36  	first := 2
    37  	gqlAfter := graphql.PageCursor("test")
    38  	searchTerm := ""
    39  	testFirstParameterMissingError := errors.New("Invalid data [reason=missing required parameter 'first']")
    40  
    41  	modelTenants := []*model.BusinessTenantMapping{
    42  		newModelBusinessTenantMapping(testID, testName),
    43  		newModelBusinessTenantMapping("test1", "name1"),
    44  	}
    45  
    46  	modelTenantsPage := &model.BusinessTenantMappingPage{
    47  		Data: modelTenants,
    48  		PageInfo: &pagination.Page{
    49  			StartCursor: "",
    50  			EndCursor:   string(gqlAfter),
    51  			HasNextPage: true,
    52  		},
    53  		TotalCount: 3,
    54  	}
    55  
    56  	gqlTenants := []*graphql.Tenant{
    57  		newGraphQLTenant(testID, "", testName),
    58  		newGraphQLTenant("test1", "", "name1"),
    59  	}
    60  
    61  	gqlTenantsPage := &graphql.TenantPage{
    62  		Data:       gqlTenants,
    63  		TotalCount: modelTenantsPage.TotalCount,
    64  		PageInfo: &graphql.PageInfo{
    65  			StartCursor: graphql.PageCursor(modelTenantsPage.PageInfo.StartCursor),
    66  			EndCursor:   graphql.PageCursor(modelTenantsPage.PageInfo.EndCursor),
    67  			HasNextPage: modelTenantsPage.PageInfo.HasNextPage,
    68  		},
    69  	}
    70  
    71  	testCases := []struct {
    72  		Name           string
    73  		TxFn           func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
    74  		TenantSvcFn    func() *automock.BusinessTenantMappingService
    75  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
    76  		first          *int
    77  		ExpectedOutput *graphql.TenantPage
    78  		ExpectedError  error
    79  	}{
    80  		{
    81  			Name: "Success",
    82  			TxFn: txGen.ThatSucceeds,
    83  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
    84  				TenantSvc := &automock.BusinessTenantMappingService{}
    85  				TenantSvc.On("ListPageBySearchTerm", txtest.CtxWithDBMatcher(), searchTerm, first, string(gqlAfter)).Return(modelTenantsPage, nil).Once()
    86  				return TenantSvc
    87  			},
    88  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
    89  				TenantConv := &automock.BusinessTenantMappingConverter{}
    90  				TenantConv.On("MultipleToGraphQL", modelTenants).Return(gqlTenants).Once()
    91  				return TenantConv
    92  			},
    93  			first:          &first,
    94  			ExpectedOutput: gqlTenantsPage,
    95  		},
    96  		{
    97  			Name: "Returns error when getting tenants failed",
    98  			TxFn: txGen.ThatDoesntExpectCommit,
    99  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   100  				TenantSvc := &automock.BusinessTenantMappingService{}
   101  				TenantSvc.On("ListPageBySearchTerm", txtest.CtxWithDBMatcher(), searchTerm, first, string(gqlAfter)).Return(nil, testError).Once()
   102  				return TenantSvc
   103  			},
   104  			TenantConvFn:  unusedTenantConverter,
   105  			first:         &first,
   106  			ExpectedError: testError,
   107  		},
   108  		{
   109  			Name:          "Returns error when failing on begin",
   110  			TxFn:          txGen.ThatFailsOnBegin,
   111  			TenantSvcFn:   unusedTenantService,
   112  			TenantConvFn:  unusedTenantConverter,
   113  			first:         &first,
   114  			ExpectedError: testError,
   115  		},
   116  		{
   117  			Name: "Returns error when failing on commit",
   118  			TxFn: txGen.ThatFailsOnCommit,
   119  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   120  				TenantSvc := &automock.BusinessTenantMappingService{}
   121  				TenantSvc.On("ListPageBySearchTerm", txtest.CtxWithDBMatcher(), searchTerm, first, string(gqlAfter)).Return(modelTenantsPage, nil).Once()
   122  				return TenantSvc
   123  			},
   124  			TenantConvFn:  unusedTenantConverter,
   125  			first:         &first,
   126  			ExpectedError: testError,
   127  		},
   128  		{
   129  			Name: "Returns error when 'first' parameter is missing",
   130  			TxFn: txGen.ThatDoesntExpectCommit,
   131  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   132  				TenantSvc := &automock.BusinessTenantMappingService{}
   133  				TenantSvc.AssertNotCalled(t, "ListPageBySearchTerm")
   134  				return TenantSvc
   135  			},
   136  			TenantConvFn:  unusedTenantConverter,
   137  			first:         nil,
   138  			ExpectedError: testFirstParameterMissingError,
   139  		},
   140  	}
   141  
   142  	for _, testCase := range testCases {
   143  		t.Run(testCase.Name, func(t *testing.T) {
   144  			tenantSvc := testCase.TenantSvcFn()
   145  			tenantConv := testCase.TenantConvFn()
   146  			persist, transact := testCase.TxFn()
   147  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   148  
   149  			// WHEN
   150  			result, err := resolver.Tenants(ctx, testCase.first, &gqlAfter, &searchTerm)
   151  
   152  			// THEN
   153  			if testCase.ExpectedError != nil {
   154  				require.Error(t, err)
   155  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   156  			} else {
   157  				assert.NoError(t, err)
   158  			}
   159  			assert.Equal(t, testCase.ExpectedOutput, result)
   160  
   161  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
   162  		})
   163  	}
   164  }
   165  
   166  func TestResolver_Tenant(t *testing.T) {
   167  	// GIVEN
   168  	ctx := context.TODO()
   169  	txGen := txtest.NewTransactionContextGenerator(testError)
   170  
   171  	tenantParent := ""
   172  	tenantInternalID := "internal"
   173  
   174  	tenantNotFoundError := apperrors.NewNotFoundError(resource.Tenant, testExternal)
   175  
   176  	expectedTenantModel := &model.BusinessTenantMapping{
   177  		ID:             testExternal,
   178  		Name:           testName,
   179  		ExternalTenant: testExternal,
   180  		Parent:         tenantParent,
   181  		Type:           tnt.Account,
   182  		Provider:       testProvider,
   183  		Status:         tnt.Active,
   184  		Initialized:    nil,
   185  	}
   186  
   187  	expectedTenantGQL := &graphql.Tenant{
   188  		ID:          testExternal,
   189  		InternalID:  tenantInternalID,
   190  		Name:        str.Ptr(testName),
   191  		Type:        string(tnt.Account),
   192  		ParentID:    tenantParent,
   193  		Initialized: nil,
   194  		Labels:      nil,
   195  	}
   196  
   197  	testCases := []struct {
   198  		Name           string
   199  		TxFn           func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   200  		TenantSvcFn    func() *automock.BusinessTenantMappingService
   201  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
   202  		TenantFetcher  func() *automock.Fetcher
   203  		TenantInput    graphql.BusinessTenantMappingInput
   204  		IDInput        string
   205  		ExpectedError  error
   206  		ExpectedResult *graphql.Tenant
   207  	}{
   208  		{
   209  			Name: "Success",
   210  			TxFn: func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) {
   211  				persistenceTx, transact := txGen.ThatSucceeds()
   212  				return []*persistenceautomock.PersistenceTx{persistenceTx, {}}, transact
   213  			},
   214  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   215  				TenantSvc := &automock.BusinessTenantMappingService{}
   216  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), testExternal).Return(expectedTenantModel, nil).Once()
   217  				return TenantSvc
   218  			},
   219  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   220  				conv := &automock.BusinessTenantMappingConverter{}
   221  				conv.On("ToGraphQL", expectedTenantModel).Return(expectedTenantGQL)
   222  				return conv
   223  			},
   224  			TenantFetcher:  unusedFetcherService,
   225  			IDInput:        testExternal,
   226  			ExpectedError:  nil,
   227  			ExpectedResult: expectedTenantGQL,
   228  		},
   229  		{
   230  			Name: "Success when tenant has to be fetched",
   231  			TxFn: func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) {
   232  				persistTx := &persistenceautomock.PersistenceTx{}
   233  				persistTx.On("Commit").Return(nil).Once()
   234  				secondPersistTx := &persistenceautomock.PersistenceTx{}
   235  				secondPersistTx.On("Commit").Return(nil).Once()
   236  				transact := &persistenceautomock.Transactioner{}
   237  				transact.On("Begin").Return(persistTx, nil).Once()
   238  				transact.On("Begin").Return(secondPersistTx, nil).Once()
   239  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Once()
   240  
   241  				return []*persistenceautomock.PersistenceTx{persistTx, secondPersistTx}, transact
   242  			},
   243  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   244  				TenantSvc := &automock.BusinessTenantMappingService{}
   245  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), testExternal).Return(nil, tenantNotFoundError).Once()
   246  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), testExternal).Return(expectedTenantModel, nil).Once()
   247  				return TenantSvc
   248  			},
   249  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   250  				conv := &automock.BusinessTenantMappingConverter{}
   251  				conv.On("ToGraphQL", expectedTenantModel).Return(expectedTenantGQL)
   252  				return conv
   253  			},
   254  			TenantFetcher: func() *automock.Fetcher {
   255  				fetcher := &automock.Fetcher{}
   256  				fetcher.On("FetchOnDemand", testExternal, "").Return(nil)
   257  				return fetcher
   258  			},
   259  			IDInput:        testExternal,
   260  			ExpectedError:  nil,
   261  			ExpectedResult: expectedTenantGQL,
   262  		},
   263  		{
   264  			Name: "That returns error when can not start transaction",
   265  			TxFn: func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) {
   266  				persistenceTx, transact := txGen.ThatFailsOnBegin()
   267  				return []*persistenceautomock.PersistenceTx{persistenceTx, {}}, transact
   268  			},
   269  			TenantSvcFn:    unusedTenantService,
   270  			TenantConvFn:   unusedTenantConverter,
   271  			TenantFetcher:  unusedFetcherService,
   272  			IDInput:        testExternal,
   273  			ExpectedError:  testError,
   274  			ExpectedResult: nil,
   275  		},
   276  		{
   277  			Name: "That returns error when can not get tenant by external ID",
   278  			TxFn: func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) {
   279  				persistTx := &persistenceautomock.PersistenceTx{}
   280  				persistTx.On("Commit").Return(nil).Once()
   281  				transact := &persistenceautomock.Transactioner{}
   282  				transact.On("Begin").Return(persistTx, nil).Once()
   283  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Once()
   284  
   285  				return []*persistenceautomock.PersistenceTx{persistTx, {}}, transact
   286  			},
   287  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   288  				TenantSvc := &automock.BusinessTenantMappingService{}
   289  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), testExternal).Return(nil, tenantNotFoundError).Once()
   290  				return TenantSvc
   291  			},
   292  			TenantConvFn: unusedTenantConverter,
   293  			TenantFetcher: func() *automock.Fetcher {
   294  				fetcher := &automock.Fetcher{}
   295  				fetcher.On("FetchOnDemand", testExternal, "").Return(tenantNotFoundError)
   296  				return fetcher
   297  			},
   298  			IDInput:        testExternal,
   299  			ExpectedError:  tenantNotFoundError,
   300  			ExpectedResult: expectedTenantGQL,
   301  		},
   302  		{
   303  			Name: "That returns error when can not fetch tenant",
   304  			TxFn: func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) {
   305  				persistenceTx, transact := txGen.ThatDoesntExpectCommit()
   306  				return []*persistenceautomock.PersistenceTx{persistenceTx, {}}, transact
   307  			},
   308  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   309  				TenantSvc := &automock.BusinessTenantMappingService{}
   310  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), testExternal).Return(nil, testError).Once()
   311  				return TenantSvc
   312  			},
   313  			TenantConvFn:   unusedTenantConverter,
   314  			TenantFetcher:  unusedFetcherService,
   315  			IDInput:        testExternal,
   316  			ExpectedError:  testError,
   317  			ExpectedResult: nil,
   318  		},
   319  		{
   320  			Name: "That returns error when cannot commit",
   321  			TxFn: func() ([]*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) {
   322  				persistenceTx, transact := txGen.ThatFailsOnCommit()
   323  				return []*persistenceautomock.PersistenceTx{persistenceTx, {}}, transact
   324  			},
   325  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   326  				TenantSvc := &automock.BusinessTenantMappingService{}
   327  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), testExternal).Return(expectedTenantModel, nil).Once()
   328  				return TenantSvc
   329  			},
   330  			TenantConvFn:   unusedTenantConverter,
   331  			TenantFetcher:  unusedFetcherService,
   332  			IDInput:        testExternal,
   333  			ExpectedError:  testError,
   334  			ExpectedResult: nil,
   335  		},
   336  	}
   337  
   338  	for _, testCase := range testCases {
   339  		t.Run(testCase.Name, func(t *testing.T) {
   340  			tenantSvc := testCase.TenantSvcFn()
   341  			tenantConv := testCase.TenantConvFn()
   342  			fetcherSvc := testCase.TenantFetcher()
   343  			persistencesTx, transact := testCase.TxFn()
   344  
   345  			defer mock.AssertExpectationsForObjects(t, transact, tenantSvc, tenantConv, fetcherSvc, persistencesTx[0], persistencesTx[1])
   346  
   347  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, fetcherSvc)
   348  
   349  			// WHEN
   350  			result, err := resolver.Tenant(ctx, testCase.IDInput)
   351  
   352  			// THEN
   353  			if testCase.ExpectedError != nil {
   354  				require.Error(t, err)
   355  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   356  			} else {
   357  				assert.NoError(t, err)
   358  				assert.Equal(t, testCase.ExpectedResult, result)
   359  			}
   360  		})
   361  	}
   362  }
   363  
   364  func TestResolver_TenantByID(t *testing.T) {
   365  	// GIVEN
   366  	ctx := context.TODO()
   367  	txGen := txtest.NewTransactionContextGenerator(testError)
   368  
   369  	tenantParent := ""
   370  	tenantInternalID := "internal"
   371  
   372  	expectedTenantModel := &model.BusinessTenantMapping{
   373  		ID:             testInternal,
   374  		Name:           testName,
   375  		ExternalTenant: testInternal,
   376  		Parent:         tenantParent,
   377  		Type:           tnt.Account,
   378  		Provider:       testProvider,
   379  		Status:         tnt.Active,
   380  		Initialized:    nil,
   381  	}
   382  
   383  	expectedTenantGQL := &graphql.Tenant{
   384  		ID:          testInternal,
   385  		InternalID:  tenantInternalID,
   386  		Name:        str.Ptr(testName),
   387  		Type:        string(tnt.Account),
   388  		ParentID:    tenantParent,
   389  		Initialized: nil,
   390  		Labels:      nil,
   391  	}
   392  
   393  	testCases := []struct {
   394  		Name            string
   395  		TxFn            func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   396  		TenantSvcFn     func() *automock.BusinessTenantMappingService
   397  		TenantConvFn    func() *automock.BusinessTenantMappingConverter
   398  		InternalIDInput string
   399  		ExpectedError   error
   400  		ExpectedResult  *graphql.Tenant
   401  	}{
   402  		{
   403  			Name: "Success",
   404  			TxFn: txGen.ThatSucceeds,
   405  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   406  				TenantSvc := &automock.BusinessTenantMappingService{}
   407  				TenantSvc.On("GetTenantByID", txtest.CtxWithDBMatcher(), testInternal).Return(expectedTenantModel, nil).Once()
   408  				return TenantSvc
   409  			},
   410  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   411  				conv := &automock.BusinessTenantMappingConverter{}
   412  				conv.On("ToGraphQL", expectedTenantModel).Return(expectedTenantGQL)
   413  				return conv
   414  			},
   415  			InternalIDInput: testInternal,
   416  			ExpectedError:   nil,
   417  			ExpectedResult:  expectedTenantGQL,
   418  		},
   419  		{
   420  			Name:            "That returns error when can not start transaction",
   421  			TxFn:            txGen.ThatFailsOnBegin,
   422  			TenantSvcFn:     unusedTenantService,
   423  			TenantConvFn:    unusedTenantConverter,
   424  			InternalIDInput: testInternal,
   425  			ExpectedError:   testError,
   426  			ExpectedResult:  nil,
   427  		},
   428  		{
   429  			Name: "That returns error when can not get tenant by internal ID",
   430  			TxFn: txGen.ThatDoesntExpectCommit,
   431  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   432  				TenantSvc := &automock.BusinessTenantMappingService{}
   433  				TenantSvc.On("GetTenantByID", txtest.CtxWithDBMatcher(), testInternal).Return(nil, testError).Once()
   434  				return TenantSvc
   435  			},
   436  			TenantConvFn:    unusedTenantConverter,
   437  			InternalIDInput: testInternal,
   438  			ExpectedError:   testError,
   439  			ExpectedResult:  nil,
   440  		},
   441  		{
   442  			Name: "That returns error when cannot commit",
   443  			TxFn: txGen.ThatFailsOnCommit,
   444  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   445  				TenantSvc := &automock.BusinessTenantMappingService{}
   446  				TenantSvc.On("GetTenantByID", txtest.CtxWithDBMatcher(), testInternal).Return(expectedTenantModel, nil).Once()
   447  				return TenantSvc
   448  			},
   449  			TenantConvFn:    unusedTenantConverter,
   450  			InternalIDInput: testInternal,
   451  			ExpectedError:   testError,
   452  			ExpectedResult:  nil,
   453  		},
   454  	}
   455  
   456  	for _, testCase := range testCases {
   457  		t.Run(testCase.Name, func(t *testing.T) {
   458  			tenantSvc := testCase.TenantSvcFn()
   459  			tenantConv := testCase.TenantConvFn()
   460  			persist, transact := testCase.TxFn()
   461  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   462  
   463  			// WHEN
   464  			result, err := resolver.TenantByID(ctx, testCase.InternalIDInput)
   465  
   466  			// THEN
   467  			if testCase.ExpectedError != nil {
   468  				require.Error(t, err)
   469  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   470  			} else {
   471  				assert.NoError(t, err)
   472  				assert.Equal(t, testCase.ExpectedResult, result)
   473  			}
   474  
   475  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
   476  		})
   477  	}
   478  }
   479  
   480  func TestResolver_TenantByLowestOwnerForResource(t *testing.T) {
   481  	// GIVEN
   482  	ctx := context.TODO()
   483  	txGen := txtest.NewTransactionContextGenerator(testError)
   484  
   485  	resourceTypeStr := "application"
   486  	resourceType := resource.Type(resourceTypeStr)
   487  	objectID := "objectID"
   488  
   489  	testCases := []struct {
   490  		Name           string
   491  		TxFn           func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   492  		TenantSvcFn    func() *automock.BusinessTenantMappingService
   493  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
   494  		ExpectedError  error
   495  		ExpectedResult string
   496  	}{
   497  		{
   498  			Name: "Success",
   499  			TxFn: txGen.ThatSucceeds,
   500  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   501  				TenantSvc := &automock.BusinessTenantMappingService{}
   502  				TenantSvc.On("GetLowestOwnerForResource", txtest.CtxWithDBMatcher(), resourceType, objectID).Return(testInternal, nil).Once()
   503  				return TenantSvc
   504  			},
   505  			TenantConvFn:   unusedTenantConverter,
   506  			ExpectedError:  nil,
   507  			ExpectedResult: testInternal,
   508  		},
   509  		{
   510  			Name:           "That returns error when can not start transaction",
   511  			TxFn:           txGen.ThatFailsOnBegin,
   512  			TenantSvcFn:    unusedTenantService,
   513  			TenantConvFn:   unusedTenantConverter,
   514  			ExpectedError:  testError,
   515  			ExpectedResult: "",
   516  		},
   517  		{
   518  			Name: "That returns error when can not get lowest owner for resource",
   519  			TxFn: txGen.ThatDoesntExpectCommit,
   520  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   521  				TenantSvc := &automock.BusinessTenantMappingService{}
   522  				TenantSvc.On("GetLowestOwnerForResource", txtest.CtxWithDBMatcher(), resourceType, objectID).Return("", testError).Once()
   523  				return TenantSvc
   524  			},
   525  			TenantConvFn:   unusedTenantConverter,
   526  			ExpectedError:  testError,
   527  			ExpectedResult: "",
   528  		},
   529  		{
   530  			Name: "That returns error when cannot commit",
   531  			TxFn: txGen.ThatFailsOnCommit,
   532  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   533  				TenantSvc := &automock.BusinessTenantMappingService{}
   534  				TenantSvc.On("GetLowestOwnerForResource", txtest.CtxWithDBMatcher(), resourceType, objectID).Return(testInternal, nil).Once()
   535  				return TenantSvc
   536  			},
   537  			TenantConvFn:   unusedTenantConverter,
   538  			ExpectedError:  testError,
   539  			ExpectedResult: testInternal,
   540  		},
   541  	}
   542  
   543  	for _, testCase := range testCases {
   544  		t.Run(testCase.Name, func(t *testing.T) {
   545  			tenantSvc := testCase.TenantSvcFn()
   546  			tenantConv := testCase.TenantConvFn()
   547  			persist, transact := testCase.TxFn()
   548  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   549  
   550  			// WHEN
   551  			tenantID, err := resolver.TenantByLowestOwnerForResource(ctx, resourceTypeStr, objectID)
   552  
   553  			// THEN
   554  			if testCase.ExpectedError != nil {
   555  				require.Error(t, err)
   556  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   557  			} else {
   558  				assert.NoError(t, err)
   559  				assert.Equal(t, testCase.ExpectedResult, tenantID)
   560  			}
   561  
   562  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
   563  		})
   564  	}
   565  }
   566  
   567  func TestResolver_Labels(t *testing.T) {
   568  	// GIVEN
   569  	ctx := context.TODO()
   570  
   571  	txGen := txtest.NewTransactionContextGenerator(testError)
   572  
   573  	tenantID := "2af44425-d02d-4aed-9086-b0fc3122b508"
   574  	testTenant := &graphql.Tenant{ID: "externalID", InternalID: tenantID}
   575  
   576  	testLabelKey := "my-key"
   577  	testLabels := map[string]*model.Label{
   578  		testLabelKey: {
   579  			ID:         "5d0ec128-47da-418a-99f5-8409105ce82d",
   580  			Tenant:     str.Ptr(tenantID),
   581  			Key:        testLabelKey,
   582  			Value:      "value",
   583  			ObjectID:   tenantID,
   584  			ObjectType: model.TenantLabelableObject,
   585  		},
   586  	}
   587  
   588  	t.Run("Succeeds", func(t *testing.T) {
   589  		tenantSvc := unusedTenantService()
   590  		tenantSvc.On("ListLabels", txtest.CtxWithDBMatcher(), testTenant.InternalID).Return(testLabels, nil)
   591  		tenantConv := unusedTenantConverter()
   592  		persist, transact := txGen.ThatSucceeds()
   593  
   594  		defer mock.AssertExpectationsForObjects(t, tenantSvc, tenantConv, persist, transact)
   595  
   596  		resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   597  
   598  		result, err := resolver.Labels(ctx, testTenant, nil)
   599  		assert.NoError(t, err)
   600  
   601  		assert.NotNil(t, result)
   602  		assert.Len(t, result, len(testLabels))
   603  		assert.Equal(t, testLabels[testLabelKey].Value, result[testLabelKey])
   604  	})
   605  	t.Run("Succeeds when labels do not exist", func(t *testing.T) {
   606  		tenantSvc := unusedTenantService()
   607  		tenantSvc.On("ListLabels", txtest.CtxWithDBMatcher(), testTenant.InternalID).Return(nil, apperrors.NewNotFoundError(resource.Tenant, testTenant.InternalID))
   608  		tenantConv := unusedTenantConverter()
   609  		persist, transact := txGen.ThatSucceeds()
   610  
   611  		defer mock.AssertExpectationsForObjects(t, tenantSvc, tenantConv, persist, transact)
   612  
   613  		resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   614  
   615  		labels, err := resolver.Labels(ctx, testTenant, nil)
   616  		assert.NoError(t, err)
   617  		assert.Nil(t, labels)
   618  	})
   619  	t.Run("Returns error when the provided tenant is nil", func(t *testing.T) {
   620  		tenantSvc := unusedTenantService()
   621  		tenantConv := unusedTenantConverter()
   622  		persist, transact := txGen.ThatDoesntStartTransaction()
   623  
   624  		defer mock.AssertExpectationsForObjects(t, tenantSvc, tenantConv, persist, transact)
   625  
   626  		resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   627  
   628  		_, err := resolver.Labels(ctx, nil, nil)
   629  		assert.Error(t, err)
   630  		assert.Contains(t, err.Error(), "Tenant cannot be empty")
   631  	})
   632  	t.Run("Returns error when starting transaction fails", func(t *testing.T) {
   633  		tenantSvc := unusedTenantService()
   634  		tenantConv := unusedTenantConverter()
   635  		persist, transact := txGen.ThatFailsOnBegin()
   636  
   637  		defer mock.AssertExpectationsForObjects(t, tenantSvc, tenantConv, persist, transact)
   638  
   639  		resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   640  
   641  		result, err := resolver.Labels(ctx, testTenant, nil)
   642  		assert.Error(t, err)
   643  		assert.Nil(t, result)
   644  	})
   645  	t.Run("Returns error when it fails to list labels", func(t *testing.T) {
   646  		tenantSvc := unusedTenantService()
   647  		tenantSvc.On("ListLabels", txtest.CtxWithDBMatcher(), testTenant.InternalID).Return(nil, testError)
   648  		tenantConv := unusedTenantConverter()
   649  		persist, transact := txGen.ThatDoesntExpectCommit()
   650  
   651  		defer mock.AssertExpectationsForObjects(t, tenantSvc, tenantConv, persist, transact)
   652  
   653  		resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   654  
   655  		_, err := resolver.Labels(ctx, testTenant, nil)
   656  		assert.Error(t, err)
   657  		assert.Equal(t, testError, err)
   658  	})
   659  	t.Run("Returns error when commit fails", func(t *testing.T) {
   660  		tenantSvc := unusedTenantService()
   661  		tenantSvc.On("ListLabels", txtest.CtxWithDBMatcher(), testTenant.InternalID).Return(testLabels, nil)
   662  		tenantConv := unusedTenantConverter()
   663  		persist, transact := txGen.ThatFailsOnCommit()
   664  
   665  		defer mock.AssertExpectationsForObjects(t, tenantSvc, tenantConv, persist, transact)
   666  
   667  		resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   668  
   669  		_, err := resolver.Labels(ctx, testTenant, nil)
   670  		assert.Error(t, err)
   671  		assert.Equal(t, testError, err)
   672  	})
   673  }
   674  
   675  func TestResolver_Write(t *testing.T) {
   676  	// GIVEN
   677  	ctx := context.TODO()
   678  	txGen := txtest.NewTransactionContextGenerator(testError)
   679  
   680  	tenantNames := []string{"name1", "name2"}
   681  	tenantExternalTenants := []string{"external1", "external2"}
   682  	tenantParent := ""
   683  	tenantSubdomain := "subdomain"
   684  	tenantRegion := "region"
   685  	tenantProvider := "test"
   686  
   687  	tenantsToUpsertGQL := []*graphql.BusinessTenantMappingInput{
   688  		{
   689  			Name:           tenantNames[0],
   690  			ExternalTenant: tenantExternalTenants[0],
   691  			Parent:         str.Ptr(tenantParent),
   692  			Subdomain:      str.Ptr(tenantSubdomain),
   693  			Region:         str.Ptr(tenantRegion),
   694  			Type:           string(tnt.Account),
   695  			Provider:       tenantProvider,
   696  		},
   697  		{
   698  			Name:           tenantNames[1],
   699  			ExternalTenant: tenantExternalTenants[1],
   700  			Parent:         str.Ptr(tenantParent),
   701  			Subdomain:      str.Ptr(tenantSubdomain),
   702  			Region:         str.Ptr(tenantRegion),
   703  			Type:           string(tnt.Account),
   704  			Provider:       tenantProvider,
   705  		},
   706  	}
   707  	tenantsToUpsertModel := []model.BusinessTenantMappingInput{
   708  		{
   709  			Name:           tenantNames[0],
   710  			ExternalTenant: tenantExternalTenants[0],
   711  			Parent:         tenantParent,
   712  			Subdomain:      tenantSubdomain,
   713  			Region:         tenantRegion,
   714  			Type:           string(tnt.Account),
   715  			Provider:       tenantProvider,
   716  		},
   717  		{
   718  			Name:           tenantNames[1],
   719  			ExternalTenant: tenantExternalTenants[1],
   720  			Parent:         tenantParent,
   721  			Subdomain:      tenantSubdomain,
   722  			Region:         tenantRegion,
   723  			Type:           string(tnt.Account),
   724  			Provider:       tenantProvider,
   725  		},
   726  	}
   727  
   728  	upsertedTenantsIDs := []string{"6f4a589c-ac2e-4870-acb5-5a58abc85c6a", "eace9a3a-383b-44d1-8864-7e951ac5ec06"}
   729  
   730  	testCases := []struct {
   731  		Name           string
   732  		TxFn           func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   733  		TenantSvcFn    func() *automock.BusinessTenantMappingService
   734  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
   735  		TenantsInput   []*graphql.BusinessTenantMappingInput
   736  		ExpectedError  error
   737  		ExpectedResult []string
   738  	}{
   739  		{
   740  			Name: "Success",
   741  			TxFn: txGen.ThatSucceeds,
   742  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   743  				TenantSvc := unusedTenantService()
   744  				TenantSvc.On("UpsertMany", txtest.CtxWithDBMatcher(), tenantsToUpsertModel[0], tenantsToUpsertModel[1]).Return(upsertedTenantsIDs, nil).Once()
   745  				return TenantSvc
   746  			},
   747  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   748  				TenantConv := &automock.BusinessTenantMappingConverter{}
   749  				TenantConv.On("MultipleInputFromGraphQL", tenantsToUpsertGQL).Return(tenantsToUpsertModel).Once()
   750  				return TenantConv
   751  			},
   752  			TenantsInput:   tenantsToUpsertGQL,
   753  			ExpectedError:  nil,
   754  			ExpectedResult: upsertedTenantsIDs,
   755  		},
   756  		{
   757  			Name:           "Returns error when can not start transaction",
   758  			TxFn:           txGen.ThatFailsOnBegin,
   759  			TenantSvcFn:    unusedTenantService,
   760  			TenantConvFn:   unusedTenantConverter,
   761  			TenantsInput:   tenantsToUpsertGQL,
   762  			ExpectedError:  testError,
   763  			ExpectedResult: nil,
   764  		},
   765  		{
   766  			Name: "Returns error when can not create the tenants",
   767  			TxFn: txGen.ThatDoesntExpectCommit,
   768  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   769  				TenantSvc := &automock.BusinessTenantMappingService{}
   770  				TenantSvc.On("UpsertMany", txtest.CtxWithDBMatcher(), tenantsToUpsertModel[0], tenantsToUpsertModel[1]).Return(nil, testError).Once()
   771  				return TenantSvc
   772  			},
   773  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   774  				TenantConv := &automock.BusinessTenantMappingConverter{}
   775  				TenantConv.On("MultipleInputFromGraphQL", tenantsToUpsertGQL).Return(tenantsToUpsertModel).Once()
   776  				return TenantConv
   777  			},
   778  			TenantsInput:   tenantsToUpsertGQL,
   779  			ExpectedError:  testError,
   780  			ExpectedResult: nil,
   781  		},
   782  		{
   783  			Name: "Returns error when can not commit",
   784  			TxFn: txGen.ThatFailsOnCommit,
   785  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   786  				TenantSvc := &automock.BusinessTenantMappingService{}
   787  				TenantSvc.On("UpsertMany", txtest.CtxWithDBMatcher(), tenantsToUpsertModel[0], tenantsToUpsertModel[1]).Return(upsertedTenantsIDs, nil).Once()
   788  				return TenantSvc
   789  			},
   790  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   791  				TenantConv := &automock.BusinessTenantMappingConverter{}
   792  				TenantConv.On("MultipleInputFromGraphQL", tenantsToUpsertGQL).Return(tenantsToUpsertModel).Once()
   793  				return TenantConv
   794  			},
   795  			TenantsInput:   tenantsToUpsertGQL,
   796  			ExpectedError:  testError,
   797  			ExpectedResult: nil,
   798  		},
   799  	}
   800  
   801  	for _, testCase := range testCases {
   802  		t.Run(testCase.Name, func(t *testing.T) {
   803  			tenantSvc := testCase.TenantSvcFn()
   804  			tenantConv := testCase.TenantConvFn()
   805  			persist, transact := testCase.TxFn()
   806  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   807  
   808  			// WHEN
   809  			result, err := resolver.Write(ctx, testCase.TenantsInput)
   810  
   811  			// THEN
   812  			if testCase.ExpectedError != nil {
   813  				require.Error(t, err)
   814  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   815  			} else {
   816  				assert.NoError(t, err)
   817  				assert.Equal(t, testCase.ExpectedResult, result)
   818  			}
   819  
   820  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
   821  		})
   822  	}
   823  }
   824  
   825  func TestResolver_WriteSingle(t *testing.T) {
   826  	ctx := context.TODO()
   827  	txGen := txtest.NewTransactionContextGenerator(testError)
   828  
   829  	tenantName := "name1"
   830  	tenantExternalTenant := "external1"
   831  	tenantParent := ""
   832  	tenantSubdomain := "subdomain"
   833  	tenantRegion := "region"
   834  	tenantProvider := "test"
   835  	tenantID := "2af44425-d02d-4aed-9086-b0fc3122b508"
   836  
   837  	tenantToUpsertGQL := graphql.BusinessTenantMappingInput{
   838  		Name:           tenantName,
   839  		ExternalTenant: tenantExternalTenant,
   840  		Parent:         str.Ptr(tenantParent),
   841  		Subdomain:      str.Ptr(tenantSubdomain),
   842  		Region:         str.Ptr(tenantRegion),
   843  		Type:           string(tnt.Account),
   844  		Provider:       tenantProvider,
   845  	}
   846  	tenantToUpsertModel := model.BusinessTenantMappingInput{
   847  		Name:           tenantName,
   848  		ExternalTenant: tenantExternalTenant,
   849  		Parent:         tenantParent,
   850  		Subdomain:      tenantSubdomain,
   851  		Region:         tenantRegion,
   852  		Type:           string(tnt.Account),
   853  		Provider:       tenantProvider,
   854  	}
   855  
   856  	testCases := []struct {
   857  		Name           string
   858  		TxFn           func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   859  		TenantSvcFn    func() *automock.BusinessTenantMappingService
   860  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
   861  		TenantsInput   graphql.BusinessTenantMappingInput
   862  		ExpectedError  error
   863  		ExpectedResult string
   864  	}{
   865  		{
   866  			Name: "Success",
   867  			TxFn: txGen.ThatSucceeds,
   868  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   869  				tenantSvc := unusedTenantService()
   870  				tenantSvc.On("UpsertSingle", txtest.CtxWithDBMatcher(), tenantToUpsertModel).Return(tenantID, nil).Once()
   871  				return tenantSvc
   872  			},
   873  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   874  				tenantConv := &automock.BusinessTenantMappingConverter{}
   875  				tenantConv.On("InputFromGraphQL", tenantToUpsertGQL).Return(tenantToUpsertModel).Once()
   876  				return tenantConv
   877  			},
   878  			TenantsInput:   tenantToUpsertGQL,
   879  			ExpectedError:  nil,
   880  			ExpectedResult: tenantID,
   881  		},
   882  		{
   883  			Name:           "Returns error when can not start transaction",
   884  			TxFn:           txGen.ThatFailsOnBegin,
   885  			TenantSvcFn:    unusedTenantService,
   886  			TenantConvFn:   unusedTenantConverter,
   887  			TenantsInput:   tenantToUpsertGQL,
   888  			ExpectedError:  testError,
   889  			ExpectedResult: "",
   890  		},
   891  		{
   892  			Name: "Error when upserting",
   893  			TxFn: txGen.ThatDoesntExpectCommit,
   894  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   895  				tenantSvc := unusedTenantService()
   896  				tenantSvc.On("UpsertSingle", txtest.CtxWithDBMatcher(), tenantToUpsertModel).Return("", testError).Once()
   897  				return tenantSvc
   898  			},
   899  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   900  				tenantConv := &automock.BusinessTenantMappingConverter{}
   901  				tenantConv.On("InputFromGraphQL", tenantToUpsertGQL).Return(tenantToUpsertModel).Once()
   902  				return tenantConv
   903  			},
   904  			TenantsInput:   tenantToUpsertGQL,
   905  			ExpectedError:  testError,
   906  			ExpectedResult: "",
   907  		},
   908  		{
   909  			Name: "Returns error when fails to commit",
   910  			TxFn: txGen.ThatFailsOnCommit,
   911  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   912  				tenantSvc := &automock.BusinessTenantMappingService{}
   913  				tenantSvc.On("UpsertSingle", txtest.CtxWithDBMatcher(), tenantToUpsertModel).Return(tenantID, nil).Once()
   914  				return tenantSvc
   915  			},
   916  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
   917  				tenantConv := &automock.BusinessTenantMappingConverter{}
   918  				tenantConv.On("InputFromGraphQL", tenantToUpsertGQL).Return(tenantToUpsertModel).Once()
   919  				return tenantConv
   920  			},
   921  			TenantsInput:   tenantToUpsertGQL,
   922  			ExpectedError:  testError,
   923  			ExpectedResult: "",
   924  		},
   925  	}
   926  
   927  	for _, testCase := range testCases {
   928  		t.Run(testCase.Name, func(t *testing.T) {
   929  			tenantSvc := testCase.TenantSvcFn()
   930  			tenantConv := testCase.TenantConvFn()
   931  			persist, transact := testCase.TxFn()
   932  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
   933  
   934  			// WHEN
   935  			result, err := resolver.WriteSingle(ctx, testCase.TenantsInput)
   936  
   937  			// THEN
   938  			if testCase.ExpectedError != nil {
   939  				require.Error(t, err)
   940  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   941  			} else {
   942  				assert.NoError(t, err)
   943  				assert.Equal(t, testCase.ExpectedResult, result)
   944  			}
   945  
   946  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
   947  		})
   948  	}
   949  }
   950  
   951  func TestResolver_Delete(t *testing.T) {
   952  	// GIVEN
   953  	ctx := context.TODO()
   954  	txGen := txtest.NewTransactionContextGenerator(testError)
   955  
   956  	tenantExternalTenants := []string{"external1", "external2"}
   957  
   958  	testCases := []struct {
   959  		Name           string
   960  		TxFn           func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   961  		TenantSvcFn    func() *automock.BusinessTenantMappingService
   962  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
   963  		TenantsInput   []string
   964  		ExpectedError  error
   965  		ExpectedResult int
   966  	}{
   967  		{
   968  			Name: "Success",
   969  			TxFn: txGen.ThatSucceeds,
   970  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   971  				TenantSvc := &automock.BusinessTenantMappingService{}
   972  				TenantSvc.On("DeleteMany", txtest.CtxWithDBMatcher(), tenantExternalTenants).Return(nil).Once()
   973  				return TenantSvc
   974  			},
   975  			TenantConvFn:   unusedTenantConverter,
   976  			TenantsInput:   tenantExternalTenants,
   977  			ExpectedError:  nil,
   978  			ExpectedResult: 2,
   979  		},
   980  		{
   981  			Name:           "Returns error when can not start transaction",
   982  			TxFn:           txGen.ThatFailsOnBegin,
   983  			TenantSvcFn:    unusedTenantService,
   984  			TenantConvFn:   unusedTenantConverter,
   985  			TenantsInput:   tenantExternalTenants,
   986  			ExpectedError:  testError,
   987  			ExpectedResult: -1,
   988  		},
   989  		{
   990  			Name: "Returns error when can not create the tenants",
   991  			TxFn: txGen.ThatDoesntExpectCommit,
   992  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
   993  				TenantSvc := &automock.BusinessTenantMappingService{}
   994  				TenantSvc.On("DeleteMany", txtest.CtxWithDBMatcher(), tenantExternalTenants).Return(testError).Once()
   995  				return TenantSvc
   996  			},
   997  			TenantConvFn:   unusedTenantConverter,
   998  			TenantsInput:   tenantExternalTenants,
   999  			ExpectedError:  testError,
  1000  			ExpectedResult: -1,
  1001  		},
  1002  		{
  1003  			Name: "Returns error when can not commit",
  1004  			TxFn: txGen.ThatFailsOnCommit,
  1005  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1006  				TenantSvc := &automock.BusinessTenantMappingService{}
  1007  				TenantSvc.On("DeleteMany", txtest.CtxWithDBMatcher(), tenantExternalTenants).Return(nil).Once()
  1008  				return TenantSvc
  1009  			},
  1010  			TenantConvFn:   unusedTenantConverter,
  1011  			TenantsInput:   tenantExternalTenants,
  1012  			ExpectedError:  testError,
  1013  			ExpectedResult: -1,
  1014  		},
  1015  	}
  1016  
  1017  	for _, testCase := range testCases {
  1018  		t.Run(testCase.Name, func(t *testing.T) {
  1019  			tenantSvc := testCase.TenantSvcFn()
  1020  			tenantConv := testCase.TenantConvFn()
  1021  			persist, transact := testCase.TxFn()
  1022  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
  1023  
  1024  			// WHEN
  1025  			result, err := resolver.Delete(ctx, testCase.TenantsInput)
  1026  
  1027  			// THEN
  1028  			if testCase.ExpectedError != nil {
  1029  				require.Error(t, err)
  1030  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1031  			} else {
  1032  				assert.NoError(t, err)
  1033  				assert.Equal(t, testCase.ExpectedResult, result)
  1034  			}
  1035  
  1036  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
  1037  		})
  1038  	}
  1039  }
  1040  
  1041  func TestResolver_Update(t *testing.T) {
  1042  	// GIVEN
  1043  	ctx := context.TODO()
  1044  	txGen := txtest.NewTransactionContextGenerator(testError)
  1045  
  1046  	tenantParent := ""
  1047  	tenantInternalID := "internal"
  1048  
  1049  	tenantsToUpdateGQL := []*graphql.BusinessTenantMappingInput{
  1050  		{
  1051  			Name:           testName,
  1052  			ExternalTenant: testExternal,
  1053  			Parent:         str.Ptr(tenantParent),
  1054  			Subdomain:      str.Ptr(testSubdomain),
  1055  			Region:         str.Ptr(testRegion),
  1056  			Type:           string(tnt.Account),
  1057  			Provider:       testProvider,
  1058  		},
  1059  	}
  1060  
  1061  	tenantsToUpdateModel := []model.BusinessTenantMappingInput{
  1062  		{
  1063  			Name:           testName,
  1064  			ExternalTenant: testExternal,
  1065  			Parent:         tenantParent,
  1066  			Subdomain:      testSubdomain,
  1067  			Region:         testRegion,
  1068  			Type:           string(tnt.Account),
  1069  			Provider:       testProvider,
  1070  		},
  1071  	}
  1072  
  1073  	expectedTenantModel := &model.BusinessTenantMapping{
  1074  		ID:             testExternal,
  1075  		Name:           testName,
  1076  		ExternalTenant: testExternal,
  1077  		Parent:         tenantParent,
  1078  		Type:           tnt.Account,
  1079  		Provider:       testProvider,
  1080  		Status:         tnt.Active,
  1081  		Initialized:    nil,
  1082  	}
  1083  
  1084  	expectedTenantGQL := &graphql.Tenant{
  1085  		ID:          testExternal,
  1086  		InternalID:  tenantInternalID,
  1087  		Name:        str.Ptr(testName),
  1088  		Type:        string(tnt.Account),
  1089  		ParentID:    tenantParent,
  1090  		Initialized: nil,
  1091  		Labels:      nil,
  1092  	}
  1093  
  1094  	testCases := []struct {
  1095  		Name           string
  1096  		TxFn           func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
  1097  		TenantSvcFn    func() *automock.BusinessTenantMappingService
  1098  		TenantConvFn   func() *automock.BusinessTenantMappingConverter
  1099  		TenantInput    graphql.BusinessTenantMappingInput
  1100  		IDInput        string
  1101  		ExpectedError  error
  1102  		ExpectedResult *graphql.Tenant
  1103  	}{
  1104  		{
  1105  			Name: "Success",
  1106  			TxFn: txGen.ThatSucceeds,
  1107  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1108  				TenantSvc := &automock.BusinessTenantMappingService{}
  1109  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), tenantsToUpdateGQL[0].ExternalTenant).Return(expectedTenantModel, nil).Once()
  1110  				TenantSvc.On("Update", txtest.CtxWithDBMatcher(), tenantInternalID, tenantsToUpdateModel[0]).Return(nil).Once()
  1111  				return TenantSvc
  1112  			},
  1113  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1114  				conv := &automock.BusinessTenantMappingConverter{}
  1115  				conv.On("MultipleInputFromGraphQL", tenantsToUpdateGQL).Return(tenantsToUpdateModel)
  1116  				conv.On("ToGraphQL", expectedTenantModel).Return(expectedTenantGQL)
  1117  				return conv
  1118  			},
  1119  			TenantInput:    *tenantsToUpdateGQL[0],
  1120  			IDInput:        tenantInternalID,
  1121  			ExpectedError:  nil,
  1122  			ExpectedResult: expectedTenantGQL,
  1123  		},
  1124  		{
  1125  			Name:           "Returns error when can not start transaction",
  1126  			TxFn:           txGen.ThatFailsOnBegin,
  1127  			TenantSvcFn:    unusedTenantService,
  1128  			TenantConvFn:   unusedTenantConverter,
  1129  			TenantInput:    *tenantsToUpdateGQL[0],
  1130  			IDInput:        tenantInternalID,
  1131  			ExpectedError:  testError,
  1132  			ExpectedResult: nil,
  1133  		},
  1134  		{
  1135  			Name: "Returns error when updating tenant fails",
  1136  			TxFn: txGen.ThatDoesntExpectCommit,
  1137  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1138  				TenantSvc := &automock.BusinessTenantMappingService{}
  1139  				TenantSvc.On("Update", txtest.CtxWithDBMatcher(), tenantInternalID, tenantsToUpdateModel[0]).Return(testError).Once()
  1140  				return TenantSvc
  1141  			},
  1142  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1143  				conv := &automock.BusinessTenantMappingConverter{}
  1144  				conv.On("MultipleInputFromGraphQL", tenantsToUpdateGQL).Return(tenantsToUpdateModel)
  1145  				return conv
  1146  			},
  1147  			TenantInput:    *tenantsToUpdateGQL[0],
  1148  			IDInput:        tenantInternalID,
  1149  			ExpectedError:  testError,
  1150  			ExpectedResult: nil,
  1151  		},
  1152  		{
  1153  			Name: "Returns error when can not get tenant by external ID",
  1154  			TxFn: txGen.ThatDoesntExpectCommit,
  1155  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1156  				TenantSvc := &automock.BusinessTenantMappingService{}
  1157  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), tenantsToUpdateGQL[0].ExternalTenant).Return(nil, testError).Once()
  1158  				TenantSvc.On("Update", txtest.CtxWithDBMatcher(), tenantInternalID, tenantsToUpdateModel[0]).Return(nil).Once()
  1159  				return TenantSvc
  1160  			},
  1161  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1162  				conv := &automock.BusinessTenantMappingConverter{}
  1163  				conv.On("MultipleInputFromGraphQL", tenantsToUpdateGQL).Return(tenantsToUpdateModel)
  1164  				return conv
  1165  			},
  1166  			TenantInput:    *tenantsToUpdateGQL[0],
  1167  			IDInput:        tenantInternalID,
  1168  			ExpectedError:  testError,
  1169  			ExpectedResult: nil,
  1170  		},
  1171  		{
  1172  			Name: "Returns error when can not commit",
  1173  			TxFn: txGen.ThatFailsOnCommit,
  1174  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1175  				TenantSvc := &automock.BusinessTenantMappingService{}
  1176  				TenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), tenantsToUpdateGQL[0].ExternalTenant).Return(expectedTenantModel, nil).Once()
  1177  				TenantSvc.On("Update", txtest.CtxWithDBMatcher(), tenantInternalID, tenantsToUpdateModel[0]).Return(nil).Once()
  1178  				return TenantSvc
  1179  			},
  1180  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1181  				conv := &automock.BusinessTenantMappingConverter{}
  1182  				conv.On("MultipleInputFromGraphQL", tenantsToUpdateGQL).Return(tenantsToUpdateModel)
  1183  				return conv
  1184  			},
  1185  			TenantInput:    *tenantsToUpdateGQL[0],
  1186  			IDInput:        tenantInternalID,
  1187  			ExpectedError:  testError,
  1188  			ExpectedResult: nil,
  1189  		},
  1190  	}
  1191  
  1192  	for _, testCase := range testCases {
  1193  		t.Run(testCase.Name, func(t *testing.T) {
  1194  			tenantSvc := testCase.TenantSvcFn()
  1195  			tenantConv := testCase.TenantConvFn()
  1196  			persist, transact := testCase.TxFn()
  1197  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
  1198  
  1199  			// WHEN
  1200  			result, err := resolver.Update(ctx, testCase.IDInput, testCase.TenantInput)
  1201  
  1202  			// THEN
  1203  			if testCase.ExpectedError != nil {
  1204  				require.Error(t, err)
  1205  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1206  			} else {
  1207  				assert.NoError(t, err)
  1208  				assert.Equal(t, testCase.ExpectedResult, result)
  1209  			}
  1210  
  1211  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
  1212  		})
  1213  	}
  1214  }
  1215  
  1216  func TestResolver_AddTenantAccess(t *testing.T) {
  1217  	// GIVEN
  1218  	ctx := context.TODO()
  1219  	txGen := txtest.NewTransactionContextGenerator(testError)
  1220  
  1221  	testCases := []struct {
  1222  		Name             string
  1223  		TxFn             func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
  1224  		TenantSvcFn      func() *automock.BusinessTenantMappingService
  1225  		TenantConvFn     func() *automock.BusinessTenantMappingConverter
  1226  		Input            graphql.TenantAccessInput
  1227  		ExpectedErrorMsg string
  1228  		ExpectedResult   *graphql.TenantAccess
  1229  	}{
  1230  		{
  1231  			Name: "Success",
  1232  			TxFn: txGen.ThatSucceeds,
  1233  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1234  				TenantSvc := &automock.BusinessTenantMappingService{}
  1235  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1236  				TenantSvc.On("CreateTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1237  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1238  				return TenantSvc
  1239  			},
  1240  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1241  				conv := &automock.BusinessTenantMappingConverter{}
  1242  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(tenantAccessWithoutInternalTenantModel, nil).Once()
  1243  				conv.On("TenantAccessToGraphQL", tenantAccessModel).Return(tenantAccessGQL, nil).Once()
  1244  				return conv
  1245  			},
  1246  			Input:          tenantAccessInput,
  1247  			ExpectedResult: tenantAccessGQL,
  1248  		},
  1249  		{
  1250  			Name: "Error when committing transaction",
  1251  			TxFn: txGen.ThatFailsOnCommit,
  1252  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1253  				TenantSvc := &automock.BusinessTenantMappingService{}
  1254  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1255  				TenantSvc.On("CreateTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1256  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1257  				return TenantSvc
  1258  			},
  1259  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1260  				conv := &automock.BusinessTenantMappingConverter{}
  1261  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(tenantAccessWithoutInternalTenantModel, nil).Once()
  1262  				conv.On("TenantAccessToGraphQL", tenantAccessModel).Return(tenantAccessGQL, nil).Once()
  1263  				return conv
  1264  			},
  1265  			Input:            tenantAccessInput,
  1266  			ExpectedErrorMsg: testError.Error(),
  1267  		},
  1268  		{
  1269  			Name: "Error when converting to graphql",
  1270  			TxFn: txGen.ThatDoesntExpectCommit,
  1271  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1272  				TenantSvc := &automock.BusinessTenantMappingService{}
  1273  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1274  				TenantSvc.On("CreateTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1275  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1276  				return TenantSvc
  1277  			},
  1278  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1279  				conv := &automock.BusinessTenantMappingConverter{}
  1280  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(tenantAccessWithoutInternalTenantModel, nil).Once()
  1281  				conv.On("TenantAccessToGraphQL", tenantAccessModel).Return(nil, testError).Once()
  1282  				return conv
  1283  			},
  1284  			Input:            tenantAccessInput,
  1285  			ExpectedErrorMsg: "while converting to graphql tenant access",
  1286  		},
  1287  		{
  1288  			Name: "Error when getting tenant access",
  1289  			TxFn: txGen.ThatDoesntExpectCommit,
  1290  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1291  				TenantSvc := &automock.BusinessTenantMappingService{}
  1292  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1293  				TenantSvc.On("CreateTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1294  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(nil, testError).Once()
  1295  				return TenantSvc
  1296  			},
  1297  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1298  				conv := &automock.BusinessTenantMappingConverter{}
  1299  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(tenantAccessWithoutInternalTenantModel, nil).Once()
  1300  				return conv
  1301  			},
  1302  			Input:            tenantAccessInput,
  1303  			ExpectedErrorMsg: "while fetching stored tenant access for tenant",
  1304  		},
  1305  		{
  1306  			Name: "Error when creating tenant access record",
  1307  			TxFn: txGen.ThatDoesntExpectCommit,
  1308  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1309  				TenantSvc := &automock.BusinessTenantMappingService{}
  1310  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1311  				TenantSvc.On("CreateTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(testError).Once()
  1312  				return TenantSvc
  1313  			},
  1314  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1315  				conv := &automock.BusinessTenantMappingConverter{}
  1316  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(tenantAccessWithoutInternalTenantModel, nil).Once()
  1317  				return conv
  1318  			},
  1319  			Input:            tenantAccessInput,
  1320  			ExpectedErrorMsg: "while creating tenant access record",
  1321  		},
  1322  		{
  1323  			Name: "Error when getting internal tenant",
  1324  			TxFn: txGen.ThatDoesntExpectCommit,
  1325  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1326  				TenantSvc := &automock.BusinessTenantMappingService{}
  1327  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return("", testError).Once()
  1328  				return TenantSvc
  1329  			},
  1330  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1331  				conv := &automock.BusinessTenantMappingConverter{}
  1332  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(tenantAccessWithoutInternalTenantModel, nil).Once()
  1333  				return conv
  1334  			},
  1335  			Input:            tenantAccessInput,
  1336  			ExpectedErrorMsg: "while getting internal tenant",
  1337  		},
  1338  		{
  1339  			Name: "Error when converting input",
  1340  			TxFn: txGen.ThatDoesntExpectCommit,
  1341  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1342  				conv := &automock.BusinessTenantMappingConverter{}
  1343  				conv.On("TenantAccessInputFromGraphQL", tenantAccessInput).Return(nil, testError).Once()
  1344  				return conv
  1345  			},
  1346  			Input:            tenantAccessInput,
  1347  			ExpectedErrorMsg: "while converting tenant access inpu",
  1348  		},
  1349  		{
  1350  			Name:             "Error when converting input",
  1351  			TxFn:             txGen.ThatFailsOnBegin,
  1352  			Input:            tenantAccessInput,
  1353  			ExpectedErrorMsg: testError.Error(),
  1354  		},
  1355  	}
  1356  
  1357  	for _, testCase := range testCases {
  1358  		t.Run(testCase.Name, func(t *testing.T) {
  1359  			tenantSvc := unusedTenantService()
  1360  			if testCase.TenantSvcFn != nil {
  1361  				tenantSvc = testCase.TenantSvcFn()
  1362  			}
  1363  			tenantConv := unusedTenantConverter()
  1364  			if testCase.TenantConvFn != nil {
  1365  				tenantConv = testCase.TenantConvFn()
  1366  			}
  1367  			persist, transact := testCase.TxFn()
  1368  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
  1369  
  1370  			// WHEN
  1371  			result, err := resolver.AddTenantAccess(ctx, testCase.Input)
  1372  
  1373  			// THEN
  1374  			if testCase.ExpectedErrorMsg != "" {
  1375  				require.Error(t, err)
  1376  				assert.Contains(t, err.Error(), testCase.ExpectedErrorMsg)
  1377  			} else {
  1378  				assert.NoError(t, err)
  1379  				assert.Equal(t, testCase.ExpectedResult, result)
  1380  			}
  1381  
  1382  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
  1383  		})
  1384  	}
  1385  }
  1386  
  1387  func TestResolver_RemoveTenantAccess(t *testing.T) {
  1388  	// GIVEN
  1389  	ctx := context.TODO()
  1390  	txGen := txtest.NewTransactionContextGenerator(testError)
  1391  
  1392  	testCases := []struct {
  1393  		Name             string
  1394  		TxFn             func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
  1395  		TenantSvcFn      func() *automock.BusinessTenantMappingService
  1396  		TenantConvFn     func() *automock.BusinessTenantMappingConverter
  1397  		Input            graphql.TenantAccessInput
  1398  		ExpectedErrorMsg string
  1399  		ExpectedResult   *graphql.TenantAccess
  1400  	}{
  1401  		{
  1402  			Name: "Success",
  1403  			TxFn: txGen.ThatSucceeds,
  1404  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1405  				TenantSvc := &automock.BusinessTenantMappingService{}
  1406  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1407  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1408  				TenantSvc.On("DeleteTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1409  				return TenantSvc
  1410  			},
  1411  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1412  				conv := &automock.BusinessTenantMappingConverter{}
  1413  				conv.On("TenantAccessToGraphQL", tenantAccessModel).Return(tenantAccessGQL, nil).Once()
  1414  				return conv
  1415  			},
  1416  			Input:          tenantAccessInput,
  1417  			ExpectedResult: tenantAccessGQL,
  1418  		},
  1419  		{
  1420  			Name: "Error when committing transaction",
  1421  			TxFn: txGen.ThatFailsOnCommit,
  1422  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1423  				TenantSvc := &automock.BusinessTenantMappingService{}
  1424  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1425  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1426  				TenantSvc.On("DeleteTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1427  				return TenantSvc
  1428  			},
  1429  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1430  				conv := &automock.BusinessTenantMappingConverter{}
  1431  				conv.On("TenantAccessToGraphQL", tenantAccessModel).Return(tenantAccessGQL, nil).Once()
  1432  				return conv
  1433  			},
  1434  			Input:            tenantAccessInput,
  1435  			ExpectedErrorMsg: testError.Error(),
  1436  		},
  1437  		{
  1438  			Name: "Error when converting to graphql",
  1439  			TxFn: txGen.ThatDoesntExpectCommit,
  1440  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1441  				TenantSvc := &automock.BusinessTenantMappingService{}
  1442  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1443  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1444  				TenantSvc.On("DeleteTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(nil).Once()
  1445  				return TenantSvc
  1446  			},
  1447  			TenantConvFn: func() *automock.BusinessTenantMappingConverter {
  1448  				conv := &automock.BusinessTenantMappingConverter{}
  1449  				conv.On("TenantAccessToGraphQL", tenantAccessModel).Return(nil, testError).Once()
  1450  				return conv
  1451  			},
  1452  			Input:            tenantAccessInput,
  1453  			ExpectedErrorMsg: "while converting to graphql tenant access",
  1454  		},
  1455  		{
  1456  			Name: "Error when deleting tenant access record",
  1457  			TxFn: txGen.ThatDoesntExpectCommit,
  1458  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1459  				TenantSvc := &automock.BusinessTenantMappingService{}
  1460  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1461  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(tenantAccessModelWithoutExternalTenant, nil).Once()
  1462  				TenantSvc.On("DeleteTenantAccessForResourceRecursively", txtest.CtxWithDBMatcher(), tenantAccessModel).Return(testError).Once()
  1463  				return TenantSvc
  1464  			},
  1465  			Input:            tenantAccessInput,
  1466  			ExpectedErrorMsg: "while deleting tenant access record",
  1467  		},
  1468  		{
  1469  			Name: "Error when getting tenant access record",
  1470  			TxFn: txGen.ThatDoesntExpectCommit,
  1471  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1472  				TenantSvc := &automock.BusinessTenantMappingService{}
  1473  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1474  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(nil, testError).Once()
  1475  				return TenantSvc
  1476  			},
  1477  			Input:            tenantAccessInput,
  1478  			ExpectedErrorMsg: "while fetching stored tenant access for tenant",
  1479  		},
  1480  		{
  1481  			Name: "Error not found when getting tenant access record",
  1482  			TxFn: txGen.ThatDoesntExpectCommit,
  1483  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1484  				TenantSvc := &automock.BusinessTenantMappingService{}
  1485  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1486  				TenantSvc.On("GetTenantAccessForResource", txtest.CtxWithDBMatcher(), testInternal, testID, resource.Application).Return(nil, apperrors.NewNotFoundErrorWithType(resource.TenantAccess)).Once()
  1487  				return TenantSvc
  1488  			},
  1489  			Input:            tenantAccessInput,
  1490  			ExpectedErrorMsg: "Object not found [object=tenantAccess]",
  1491  		},
  1492  		{
  1493  			Name: "Error when resource type is invalid",
  1494  			TxFn: txGen.ThatDoesntExpectCommit,
  1495  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1496  				TenantSvc := &automock.BusinessTenantMappingService{}
  1497  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return(testInternal, nil).Once()
  1498  				return TenantSvc
  1499  			},
  1500  			Input:            tenantAccessInputWithInvalidResourceType,
  1501  			ExpectedErrorMsg: fmt.Sprintf("Unknown tenant access resource type %q", invalidResourceType),
  1502  		},
  1503  		{
  1504  			Name: "Error when getting internal tenant",
  1505  			TxFn: txGen.ThatDoesntExpectCommit,
  1506  			TenantSvcFn: func() *automock.BusinessTenantMappingService {
  1507  				TenantSvc := &automock.BusinessTenantMappingService{}
  1508  				TenantSvc.On("GetInternalTenant", txtest.CtxWithDBMatcher(), testExternal).Return("", testError).Once()
  1509  				return TenantSvc
  1510  			},
  1511  			Input:            tenantAccessInput,
  1512  			ExpectedErrorMsg: "while getting internal tenant",
  1513  		},
  1514  		{
  1515  			Name:             "Error when converting input",
  1516  			TxFn:             txGen.ThatFailsOnBegin,
  1517  			Input:            tenantAccessInput,
  1518  			ExpectedErrorMsg: testError.Error(),
  1519  		},
  1520  	}
  1521  
  1522  	for _, testCase := range testCases {
  1523  		t.Run(testCase.Name, func(t *testing.T) {
  1524  			tenantSvc := unusedTenantService()
  1525  			if testCase.TenantSvcFn != nil {
  1526  				tenantSvc = testCase.TenantSvcFn()
  1527  			}
  1528  			tenantConv := unusedTenantConverter()
  1529  			if testCase.TenantConvFn != nil {
  1530  				tenantConv = testCase.TenantConvFn()
  1531  			}
  1532  			persist, transact := testCase.TxFn()
  1533  			resolver := tenant.NewResolver(transact, tenantSvc, tenantConv, nil)
  1534  
  1535  			// WHEN
  1536  			result, err := resolver.RemoveTenantAccess(ctx, testCase.Input.TenantID, testCase.Input.ResourceID, testCase.Input.ResourceType)
  1537  
  1538  			// THEN
  1539  			if testCase.ExpectedErrorMsg != "" {
  1540  				require.Error(t, err)
  1541  				assert.Contains(t, err.Error(), testCase.ExpectedErrorMsg)
  1542  			} else {
  1543  				assert.NoError(t, err)
  1544  				assert.Equal(t, testCase.ExpectedResult, result)
  1545  			}
  1546  
  1547  			mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, tenantConv)
  1548  		})
  1549  	}
  1550  }