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