github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/applicationtenancy/directive_test.go (about) 1 package applicationtenancy_test 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/kyma-incubator/compass/components/director/pkg/applicationtenancy" 8 "github.com/kyma-incubator/compass/components/director/pkg/applicationtenancy/automock" 9 schema "github.com/kyma-incubator/compass/components/director/pkg/graphql" 10 persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock" 11 tenantpkg "github.com/kyma-incubator/compass/components/director/pkg/tenant" 12 "github.com/pkg/errors" 13 "github.com/stretchr/testify/mock" 14 15 "github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest" 16 17 "github.com/kyma-incubator/compass/components/director/internal/domain/tenant" 18 "github.com/kyma-incubator/compass/components/director/internal/model" 19 "github.com/kyma-incubator/compass/components/director/pkg/resource" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 ) 24 25 const ( 26 tenantID = "381060d3-39ed-4617-a14a-f6fcf52a1e7e" 27 newTenantID = "12345678-1111-4617-0000-f6fcf52a1e7e" 28 applicationID = "637060ad-f30e-4326-a8f0-6dfae63d8dc9" 29 parentTenantID = "f2cad1bc-caae-4d5b-8699-649c155a9939" 30 ) 31 32 var ( 33 testErr = errors.New("test-err") 34 subaccountTenantModel = fixBusinessTenantMappingModel(tenantID, tenantpkg.Subaccount, false) 35 rgTenantModel = fixBusinessTenantMappingModel(tenantID, tenantpkg.ResourceGroup, false) 36 accountTenantModel = fixBusinessTenantMappingModel(tenantID, tenantpkg.Account, true) 37 newAccountTenantModel = fixBusinessTenantMappingModel(newTenantID, tenantpkg.Account, true) 38 accountTenantWithoutParentModel = fixBusinessTenantMappingModel(tenantID, tenantpkg.Account, false) 39 customerTenantModel = fixBusinessTenantMappingModel(parentTenantID, tenantpkg.Customer, false) 40 tenantAccessWithOwnerTrue = fixTenantAccessModel(tenantID, applicationID, resource.Application, true) 41 tenantAccessWithOwnerFalse = fixTenantAccessModel(newTenantID, applicationID, resource.Application, false) 42 orgTenantsModel = []*model.BusinessTenantMapping{fixBusinessTenantMappingModel(tenantID, tenantpkg.Organization, true)} 43 applicationsModel = []*model.Application{fixApplicationModel(applicationID)} 44 ) 45 46 func TestDirective_TestSynchronizeApplicationTenancy(t *testing.T) { 47 testCases := []struct { 48 Name string 49 TxFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) 50 TenantSvcFn func() *automock.BusinessTenantMappingService 51 ApplicationSvcFn func() *automock.ApplicationService 52 GetCtx func() context.Context 53 Resolver func() func(ctx context.Context) (res interface{}, err error) 54 EventType schema.EventType 55 ExpectedError error 56 ExpectedResult interface{} 57 }{ 58 { 59 Name: "NEW_APPLICATION flow: Success", 60 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 61 TenantSvcFn: func() *automock.BusinessTenantMappingService { 62 tenantService := &automock.BusinessTenantMappingService{} 63 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(rgTenantModel, nil) 64 tenantService.On("GetCustomerIDParentRecursively", txtest.CtxWithDBMatcher(), tenantID).Return(parentTenantID, nil) 65 tenantService.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), parentTenantID).Return(customerTenantModel, nil) 66 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Account).Return([]*model.BusinessTenantMapping{accountTenantModel}, nil) 67 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerTrue).Return(nil) 68 69 return tenantService 70 }, 71 GetCtx: fixContextWithTenant, 72 ApplicationSvcFn: fixEmptyApplicationService, 73 Resolver: fixSuccessGraphQLApplicationResolver, 74 EventType: schema.EventTypeNewApplication, 75 ExpectedResult: mockedGraphQLApplicationNextOutput(), 76 }, 77 { 78 Name: "Should not do anything when resolver fails", 79 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntStartTransaction, 80 TenantSvcFn: fixEmptyTenantService, 81 GetCtx: fixContextWithTenant, 82 ApplicationSvcFn: fixEmptyApplicationService, 83 Resolver: fixErrorResolver, 84 EventType: schema.EventTypeNewApplication, 85 ExpectedError: testErr, 86 }, 87 { 88 Name: "Should fail when transaction fails to begin", 89 TxFn: txtest.NewTransactionContextGenerator(testErr).ThatFailsOnBegin, 90 TenantSvcFn: fixEmptyTenantService, 91 GetCtx: fixContextWithTenant, 92 ApplicationSvcFn: fixEmptyApplicationService, 93 Resolver: fixSuccessTenantResolver, 94 EventType: schema.EventTypeNewApplication, 95 ExpectedError: testErr, 96 }, 97 { 98 Name: "NEW_APPLICATION flow: Should fail when there is no tenant in the context", 99 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 100 TenantSvcFn: fixEmptyTenantService, 101 GetCtx: func() context.Context { 102 return context.TODO() 103 }, 104 ApplicationSvcFn: fixEmptyApplicationService, 105 Resolver: fixSuccessTenantResolver, 106 EventType: schema.EventTypeNewApplication, 107 ExpectedError: errors.New("cannot read tenant from context"), 108 }, 109 { 110 Name: "NEW_APPLICATION flow: Should fail when getting tenant by ID", 111 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 112 TenantSvcFn: func() *automock.BusinessTenantMappingService { 113 tenantService := &automock.BusinessTenantMappingService{} 114 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(nil, testErr) 115 return tenantService 116 }, 117 GetCtx: fixContextWithTenant, 118 ApplicationSvcFn: fixEmptyApplicationService, 119 Resolver: fixSuccessTenantResolver, 120 EventType: schema.EventTypeNewApplication, 121 ExpectedError: testErr, 122 }, 123 { 124 Name: "NEW_APPLICATION flow: Should not do anything when tenant type is not expected", 125 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 126 TenantSvcFn: func() *automock.BusinessTenantMappingService { 127 tenantService := &automock.BusinessTenantMappingService{} 128 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(subaccountTenantModel, nil) 129 return tenantService 130 }, 131 GetCtx: fixContextWithTenant, 132 ApplicationSvcFn: fixEmptyApplicationService, 133 Resolver: fixSuccessTenantResolver, 134 EventType: schema.EventTypeNewApplication, 135 ExpectedResult: mockedTenantNextOutput(), 136 }, 137 { 138 Name: "NEW_APPLICATION flow: Should fail when parsing response to graphQL entity", 139 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 140 TenantSvcFn: func() *automock.BusinessTenantMappingService { 141 tenantService := &automock.BusinessTenantMappingService{} 142 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(rgTenantModel, nil) 143 return tenantService 144 }, 145 GetCtx: fixContextWithTenant, 146 ApplicationSvcFn: fixEmptyApplicationService, 147 Resolver: fixSuccessTenantResolver, 148 EventType: schema.EventTypeNewApplication, 149 ExpectedError: errors.New("Invalid data [reason=An error occurred while casting the response entity: 12345678-1111-4617-0000-f6fcf52a1e7e]"), 150 }, 151 { 152 Name: "NEW_APPLICATION flow: Should fail when getting parent customer ID", 153 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 154 TenantSvcFn: func() *automock.BusinessTenantMappingService { 155 tenantService := &automock.BusinessTenantMappingService{} 156 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(rgTenantModel, nil) 157 tenantService.On("GetCustomerIDParentRecursively", txtest.CtxWithDBMatcher(), tenantID).Return("", testErr) 158 return tenantService 159 }, 160 GetCtx: fixContextWithTenant, 161 ApplicationSvcFn: fixEmptyApplicationService, 162 Resolver: fixSuccessGraphQLApplicationResolver, 163 EventType: schema.EventTypeNewApplication, 164 ExpectedError: testErr, 165 }, 166 { 167 Name: "NEW_APPLICATION flow: Should fail when getting tenant by external ID", 168 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 169 TenantSvcFn: func() *automock.BusinessTenantMappingService { 170 tenantService := &automock.BusinessTenantMappingService{} 171 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(rgTenantModel, nil) 172 tenantService.On("GetCustomerIDParentRecursively", txtest.CtxWithDBMatcher(), tenantID).Return(parentTenantID, nil) 173 tenantService.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), parentTenantID).Return(nil, testErr) 174 return tenantService 175 }, 176 GetCtx: fixContextWithTenant, 177 ApplicationSvcFn: fixEmptyApplicationService, 178 Resolver: fixSuccessGraphQLApplicationResolver, 179 EventType: schema.EventTypeNewApplication, 180 ExpectedError: testErr, 181 }, 182 { 183 Name: "NEW_APPLICATION flow: Should fail when listing tenant by parent and type", 184 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 185 TenantSvcFn: func() *automock.BusinessTenantMappingService { 186 tenantService := &automock.BusinessTenantMappingService{} 187 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(rgTenantModel, nil) 188 tenantService.On("GetCustomerIDParentRecursively", txtest.CtxWithDBMatcher(), tenantID).Return(parentTenantID, nil) 189 tenantService.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), parentTenantID).Return(customerTenantModel, nil) 190 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Account).Return(nil, testErr) 191 return tenantService 192 }, 193 GetCtx: fixContextWithTenant, 194 ApplicationSvcFn: fixEmptyApplicationService, 195 Resolver: fixSuccessGraphQLApplicationResolver, 196 EventType: schema.EventTypeNewApplication, 197 ExpectedError: testErr, 198 }, 199 { 200 Name: "NEW_APPLICATION flow: Should fail when creating tenant access for Application resources", 201 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 202 TenantSvcFn: func() *automock.BusinessTenantMappingService { 203 tenantService := &automock.BusinessTenantMappingService{} 204 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), tenantID).Return(rgTenantModel, nil) 205 tenantService.On("GetCustomerIDParentRecursively", txtest.CtxWithDBMatcher(), tenantID).Return(parentTenantID, nil) 206 tenantService.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), parentTenantID).Return(customerTenantModel, nil) 207 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Account).Return([]*model.BusinessTenantMapping{accountTenantModel}, nil) 208 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerTrue).Return(testErr) 209 return tenantService 210 }, 211 GetCtx: fixContextWithTenant, 212 ApplicationSvcFn: fixEmptyApplicationService, 213 Resolver: fixSuccessGraphQLApplicationResolver, 214 EventType: schema.EventTypeNewApplication, 215 ExpectedError: testErr, 216 }, 217 { 218 Name: "NEW_SINGLE_TENANT flow: Success", 219 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 220 TenantSvcFn: func() *automock.BusinessTenantMappingService { 221 tenantService := &automock.BusinessTenantMappingService{} 222 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(newAccountTenantModel, nil) 223 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 224 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerFalse).Return(nil) 225 return tenantService 226 }, 227 GetCtx: fixContextWithTenant, 228 ApplicationSvcFn: func() *automock.ApplicationService { 229 appService := &automock.ApplicationService{} 230 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(applicationsModel, nil) 231 return appService 232 }, 233 Resolver: fixSuccessTenantResolver, 234 EventType: schema.EventTypeNewSingleTenant, 235 ExpectedResult: mockedTenantNextOutput(), 236 }, 237 { 238 Name: "NEW_SINGLE_TENANT flow: Should fail when parsing response to string", 239 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 240 TenantSvcFn: fixEmptyTenantService, 241 GetCtx: fixContextWithTenant, 242 ApplicationSvcFn: fixEmptyApplicationService, 243 Resolver: fixSuccessGraphQLApplicationResolver, 244 EventType: schema.EventTypeNewSingleTenant, 245 ExpectedError: errors.New("An error occurred while casting the response entity"), 246 }, 247 { 248 Name: "NEW_SINGLE_TENANT flow: Should fail when getting tenant by ID", 249 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 250 TenantSvcFn: func() *automock.BusinessTenantMappingService { 251 tenantService := &automock.BusinessTenantMappingService{} 252 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(nil, testErr) 253 return tenantService 254 }, 255 GetCtx: fixContextWithTenant, 256 ApplicationSvcFn: fixEmptyApplicationService, 257 Resolver: fixSuccessTenantResolver, 258 EventType: schema.EventTypeNewSingleTenant, 259 ExpectedError: testErr, 260 }, 261 { 262 Name: "NEW_SINGLE_TENANT flow: Should not do anything when new tenant is not Account", 263 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 264 TenantSvcFn: func() *automock.BusinessTenantMappingService { 265 tenantService := &automock.BusinessTenantMappingService{} 266 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(subaccountTenantModel, nil) 267 return tenantService 268 }, 269 GetCtx: fixContextWithTenant, 270 ApplicationSvcFn: fixEmptyApplicationService, 271 Resolver: fixSuccessTenantResolver, 272 EventType: schema.EventTypeNewSingleTenant, 273 ExpectedResult: mockedTenantNextOutput(), 274 }, 275 { 276 Name: "NEW_SINGLE_TENANT flow: Should not do anything when new tenant is Account but does not have a parent", 277 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 278 TenantSvcFn: func() *automock.BusinessTenantMappingService { 279 tenantService := &automock.BusinessTenantMappingService{} 280 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(accountTenantWithoutParentModel, nil) 281 return tenantService 282 }, 283 GetCtx: fixContextWithTenant, 284 ApplicationSvcFn: fixEmptyApplicationService, 285 Resolver: fixSuccessTenantResolver, 286 EventType: schema.EventTypeNewSingleTenant, 287 ExpectedResult: mockedTenantNextOutput(), 288 }, 289 { 290 Name: "NEW_SINGLE_TENANT flow: Should fail when listing tenants by parent and type errors", 291 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 292 TenantSvcFn: func() *automock.BusinessTenantMappingService { 293 tenantService := &automock.BusinessTenantMappingService{} 294 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(accountTenantModel, nil) 295 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(nil, testErr) 296 return tenantService 297 }, 298 GetCtx: fixContextWithTenant, 299 ApplicationSvcFn: fixEmptyApplicationService, 300 Resolver: fixSuccessTenantResolver, 301 EventType: schema.EventTypeNewSingleTenant, 302 ExpectedError: testErr, 303 }, 304 { 305 Name: "NEW_SINGLE_TENANT flow: Should fail when listing applications for org tenant errors", 306 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 307 TenantSvcFn: func() *automock.BusinessTenantMappingService { 308 tenantService := &automock.BusinessTenantMappingService{} 309 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(accountTenantModel, nil) 310 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 311 return tenantService 312 }, 313 GetCtx: fixContextWithTenant, 314 ApplicationSvcFn: func() *automock.ApplicationService { 315 appService := &automock.ApplicationService{} 316 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(nil, testErr) 317 return appService 318 }, 319 Resolver: fixSuccessTenantResolver, 320 EventType: schema.EventTypeNewSingleTenant, 321 ExpectedError: testErr, 322 }, 323 { 324 Name: "NEW_SINGLE_TENANT flow: Should fail when creating tenant access for application errors", 325 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 326 TenantSvcFn: func() *automock.BusinessTenantMappingService { 327 tenantService := &automock.BusinessTenantMappingService{} 328 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(newAccountTenantModel, nil) 329 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 330 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerFalse).Return(testErr) 331 return tenantService 332 }, 333 GetCtx: fixContextWithTenant, 334 ApplicationSvcFn: func() *automock.ApplicationService { 335 appService := &automock.ApplicationService{} 336 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(applicationsModel, nil) 337 return appService 338 }, 339 Resolver: fixSuccessTenantResolver, 340 EventType: schema.EventTypeNewSingleTenant, 341 ExpectedError: testErr, 342 }, 343 { 344 Name: "NEW_MULTIPLE_TENANTS flow: Success", 345 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 346 TenantSvcFn: func() *automock.BusinessTenantMappingService { 347 tenantService := &automock.BusinessTenantMappingService{} 348 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(newAccountTenantModel, nil) 349 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 350 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerFalse).Return(nil) 351 return tenantService 352 }, 353 GetCtx: fixContextWithTenant, 354 ApplicationSvcFn: func() *automock.ApplicationService { 355 appService := &automock.ApplicationService{} 356 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(applicationsModel, nil) 357 return appService 358 }, 359 Resolver: fixSuccessMultipleTenantResolver, 360 EventType: schema.EventTypeNewMultipleTenants, 361 ExpectedResult: mockedMultipleTenantsNextOutput(), 362 }, 363 { 364 Name: "NEW_MULTIPLE_TENANTS flow: Should fail when parsing response to string array", 365 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 366 TenantSvcFn: fixEmptyTenantService, 367 GetCtx: fixContextWithTenant, 368 ApplicationSvcFn: fixEmptyApplicationService, 369 Resolver: fixSuccessGraphQLApplicationResolver, 370 EventType: schema.EventTypeNewMultipleTenants, 371 ExpectedError: errors.New("An error occurred while casting the response entity"), 372 }, 373 { 374 Name: "NEW_MULTIPLE_TENANTS flow: Should fail getting tenant by ID errors", 375 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 376 TenantSvcFn: func() *automock.BusinessTenantMappingService { 377 tenantService := &automock.BusinessTenantMappingService{} 378 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(nil, testErr) 379 return tenantService 380 }, 381 GetCtx: fixContextWithTenant, 382 ApplicationSvcFn: fixEmptyApplicationService, 383 Resolver: fixSuccessMultipleTenantResolver, 384 EventType: schema.EventTypeNewMultipleTenants, 385 ExpectedError: testErr, 386 }, 387 { 388 Name: "NEW_MULTIPLE_TENANTS flow: Should not do anything when tenant type is not Account", 389 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 390 TenantSvcFn: func() *automock.BusinessTenantMappingService { 391 tenantService := &automock.BusinessTenantMappingService{} 392 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(rgTenantModel, nil) 393 return tenantService 394 }, 395 GetCtx: fixContextWithTenant, 396 ApplicationSvcFn: fixEmptyApplicationService, 397 Resolver: fixSuccessMultipleTenantResolver, 398 EventType: schema.EventTypeNewMultipleTenants, 399 ExpectedResult: mockedMultipleTenantsNextOutput(), 400 }, 401 { 402 Name: "NEW_MULTIPLE_TENANTS flow: Should not do anything when tenant does not have parent", 403 TxFn: txtest.NewTransactionContextGenerator(nil).ThatSucceeds, 404 TenantSvcFn: func() *automock.BusinessTenantMappingService { 405 tenantService := &automock.BusinessTenantMappingService{} 406 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(accountTenantWithoutParentModel, nil) 407 return tenantService 408 }, 409 GetCtx: fixContextWithTenant, 410 ApplicationSvcFn: fixEmptyApplicationService, 411 Resolver: fixSuccessMultipleTenantResolver, 412 EventType: schema.EventTypeNewMultipleTenants, 413 ExpectedResult: mockedMultipleTenantsNextOutput(), 414 }, 415 { 416 Name: "NEW_MULTIPLE_TENANTS flow: Should fail when listing tenants by parent and type errors", 417 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 418 TenantSvcFn: func() *automock.BusinessTenantMappingService { 419 tenantService := &automock.BusinessTenantMappingService{} 420 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(accountTenantModel, nil) 421 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(nil, testErr) 422 return tenantService 423 }, 424 GetCtx: fixContextWithTenant, 425 ApplicationSvcFn: fixEmptyApplicationService, 426 Resolver: fixSuccessMultipleTenantResolver, 427 EventType: schema.EventTypeNewMultipleTenants, 428 ExpectedError: testErr, 429 }, 430 { 431 Name: "NEW_MULTIPLE_TENANTS flow: Should fail when listing applications for org tenant errors", 432 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 433 TenantSvcFn: func() *automock.BusinessTenantMappingService { 434 tenantService := &automock.BusinessTenantMappingService{} 435 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(accountTenantModel, nil) 436 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 437 return tenantService 438 }, 439 GetCtx: fixContextWithTenant, 440 ApplicationSvcFn: func() *automock.ApplicationService { 441 appService := &automock.ApplicationService{} 442 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(nil, testErr) 443 return appService 444 }, 445 Resolver: fixSuccessMultipleTenantResolver, 446 EventType: schema.EventTypeNewMultipleTenants, 447 ExpectedError: testErr, 448 }, 449 { 450 Name: "NEW_MULTIPLE_TENANTS flow: Should fail when creating tenant access for application errors", 451 TxFn: txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit, 452 TenantSvcFn: func() *automock.BusinessTenantMappingService { 453 tenantService := &automock.BusinessTenantMappingService{} 454 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(newAccountTenantModel, nil) 455 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 456 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerFalse).Return(testErr) 457 return tenantService 458 }, 459 GetCtx: fixContextWithTenant, 460 ApplicationSvcFn: func() *automock.ApplicationService { 461 appService := &automock.ApplicationService{} 462 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(applicationsModel, nil) 463 return appService 464 }, 465 Resolver: fixSuccessMultipleTenantResolver, 466 EventType: schema.EventTypeNewMultipleTenants, 467 ExpectedError: testErr, 468 }, 469 { 470 Name: "Should fail when committing transaction", 471 TxFn: txtest.NewTransactionContextGenerator(testErr).ThatFailsOnCommit, 472 TenantSvcFn: func() *automock.BusinessTenantMappingService { 473 tenantService := &automock.BusinessTenantMappingService{} 474 tenantService.On("GetTenantByID", txtest.CtxWithDBMatcher(), newTenantID).Return(newAccountTenantModel, nil) 475 tenantService.On("ListByParentAndType", txtest.CtxWithDBMatcher(), parentTenantID, tenantpkg.Organization).Return(orgTenantsModel, nil) 476 tenantService.On("CreateTenantAccessForResource", txtest.CtxWithDBMatcher(), tenantAccessWithOwnerFalse).Return(nil) 477 return tenantService 478 }, 479 GetCtx: fixContextWithTenant, 480 ApplicationSvcFn: func() *automock.ApplicationService { 481 appService := &automock.ApplicationService{} 482 appService.On("ListAll", txtest.CtxWithDBMatcher()).Return(applicationsModel, nil) 483 return appService 484 }, 485 Resolver: fixSuccessMultipleTenantResolver, 486 EventType: schema.EventTypeNewMultipleTenants, 487 ExpectedError: testErr, 488 }, 489 } 490 491 for _, testCase := range testCases { 492 t.Run(testCase.Name, func(t *testing.T) { 493 tenantSvc := testCase.TenantSvcFn() 494 appSvc := testCase.ApplicationSvcFn() 495 persist, transact := testCase.TxFn() 496 497 directive := applicationtenancy.NewDirective(transact, tenantSvc, appSvc) 498 499 // WHEN 500 res, err := directive.SynchronizeApplicationTenancy(testCase.GetCtx(), nil, testCase.Resolver(), testCase.EventType) 501 502 // THEN 503 if testCase.ExpectedError != nil { 504 require.Error(t, err) 505 assert.Contains(t, err.Error(), testCase.ExpectedError.Error()) 506 } else { 507 assert.NoError(t, err) 508 assert.Equal(t, testCase.ExpectedResult, res) 509 } 510 511 mock.AssertExpectationsForObjects(t, persist, transact, tenantSvc, appSvc) 512 }) 513 } 514 } 515 516 type dummyResolver struct { 517 called bool 518 } 519 520 func (d *dummyResolver) SuccessTenantResolve(_ context.Context) (res interface{}, err error) { 521 d.called = true 522 return mockedTenantNextOutput(), nil 523 } 524 525 func (d *dummyResolver) SuccessMultipleTenantResolve(_ context.Context) (res interface{}, err error) { 526 d.called = true 527 return mockedMultipleTenantsNextOutput(), nil 528 } 529 530 func (d *dummyResolver) ErrorResolve(_ context.Context) (res interface{}, err error) { 531 d.called = true 532 return nil, testErr 533 } 534 535 func (d *dummyResolver) SuccessGraphQLApplicationResolve(_ context.Context) (res interface{}, err error) { 536 d.called = true 537 return mockedGraphQLApplicationNextOutput(), nil 538 } 539 540 func mockedGraphQLApplicationNextOutput() *schema.Application { 541 return &schema.Application{ 542 BaseEntity: &schema.BaseEntity{ 543 ID: applicationID, 544 Ready: true, 545 }, 546 } 547 } 548 549 func mockedTenantNextOutput() string { 550 return newTenantID 551 } 552 553 func mockedMultipleTenantsNextOutput() []string { 554 return []string{newTenantID} 555 } 556 557 func fixSuccessGraphQLApplicationResolver() func(_ context.Context) (res interface{}, err error) { 558 r := &dummyResolver{} 559 return r.SuccessGraphQLApplicationResolve 560 } 561 562 func fixSuccessTenantResolver() func(_ context.Context) (res interface{}, err error) { 563 r := &dummyResolver{} 564 return r.SuccessTenantResolve 565 } 566 567 func fixSuccessMultipleTenantResolver() func(_ context.Context) (res interface{}, err error) { 568 r := &dummyResolver{} 569 return r.SuccessMultipleTenantResolve 570 } 571 572 func fixErrorResolver() func(_ context.Context) (res interface{}, err error) { 573 r := &dummyResolver{} 574 return r.ErrorResolve 575 } 576 577 func fixBusinessTenantMappingModel(id string, tntType tenantpkg.Type, hasParent bool) *model.BusinessTenantMapping { 578 parent := "" 579 if hasParent { 580 parent = parentTenantID 581 } 582 return &model.BusinessTenantMapping{ 583 ID: id, 584 ExternalTenant: id, 585 Type: tntType, 586 Parent: parent, 587 } 588 } 589 590 func fixApplicationModel(id string) *model.Application { 591 return &model.Application{ 592 Name: "test-app", 593 BaseEntity: &model.BaseEntity{ 594 ID: id, 595 Ready: true, 596 }, 597 } 598 } 599 600 func fixEmptyApplicationService() *automock.ApplicationService { 601 return &automock.ApplicationService{} 602 } 603 604 func fixEmptyTenantService() *automock.BusinessTenantMappingService { 605 return &automock.BusinessTenantMappingService{} 606 } 607 608 func fixContextWithTenant() context.Context { 609 return context.WithValue(context.TODO(), tenant.TenantContextKey, tenant.TenantCtx{InternalID: tenantID}) 610 } 611 612 func fixTenantAccessModel(tenantID, resourceID string, resourceType resource.Type, owner bool) *model.TenantAccess { 613 return &model.TenantAccess{ 614 InternalTenantID: tenantID, 615 ResourceType: resourceType, 616 ResourceID: resourceID, 617 Owner: owner, 618 } 619 }