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 }