github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/application/service_test.go (about) 1 package application_test 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "testing" 8 "time" 9 10 "github.com/kyma-incubator/compass/components/director/pkg/str" 11 12 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 13 "github.com/kyma-incubator/compass/components/director/pkg/operation" 14 15 "github.com/kyma-incubator/compass/components/director/pkg/normalizer" 16 17 "github.com/kyma-incubator/compass/components/director/pkg/resource" 18 19 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 20 "github.com/sirupsen/logrus" 21 22 "github.com/google/uuid" 23 "github.com/kyma-incubator/compass/components/director/internal/domain/application" 24 "github.com/kyma-incubator/compass/components/director/internal/domain/application/automock" 25 "github.com/kyma-incubator/compass/components/director/internal/domain/tenant" 26 "github.com/kyma-incubator/compass/components/director/internal/labelfilter" 27 "github.com/kyma-incubator/compass/components/director/internal/model" 28 "github.com/kyma-incubator/compass/components/director/pkg/pagination" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/mock" 31 "github.com/stretchr/testify/require" 32 ) 33 34 const testScenario = "test-scenario" 35 36 func TestService_Create(t *testing.T) { 37 // GIVEN 38 timestamp := time.Now() 39 testErr := errors.New("Test error") 40 modelInput := applicationRegisterInputWithScenarios() 41 42 normalizedModelInput := model.ApplicationRegisterInput{ 43 Name: "mp-foo-bar-not", 44 Webhooks: []*model.WebhookInput{ 45 {URL: stringPtr("test.foo.com")}, 46 {URL: stringPtr("test.bar.com")}, 47 }, 48 49 Labels: map[string]interface{}{ 50 "label": "value", 51 }, 52 IntegrationSystemID: &intSysID, 53 } 54 normalizedModelInput.Bundles = modelInput.Bundles 55 56 labels := map[string]interface{}{ 57 "integrationSystemID": intSysID, 58 "label": "value", 59 "name": "mp-foo-bar-not", 60 "applicationType": "test-app-with-ppms", 61 "ppmsProductVersionId": "1", 62 } 63 normalizedLabels := map[string]interface{}{ 64 "integrationSystemID": intSysID, 65 "label": "value", 66 "name": "mp-foo-bar-not", 67 } 68 labelsWithoutIntSys := map[string]interface{}{ 69 "integrationSystemID": "", 70 "name": "mp-test", 71 } 72 labelsWithScenarios := map[string]interface{}{ 73 "integrationSystemID": "", 74 "name": "mp-test", 75 model.ScenariosKey: []interface{}{testScenario}, 76 } 77 var nilLabels map[string]interface{} 78 79 id := "foo" 80 81 tnt := "tenant" 82 externalTnt := "external-tnt" 83 84 appModel := modelFromInput(modelInput, tnt, id, applicationMatcher(modelInput.Name, modelInput.Description)) 85 normalizedAppModel := modelFromInput(normalizedModelInput, tnt, id, applicationMatcher(normalizedModelInput.Name, normalizedModelInput.Description)) 86 87 ctx := context.TODO() 88 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 89 90 testCases := []struct { 91 Name string 92 AppNameNormalizer normalizer.Normalizator 93 AppRepoFn func() *automock.ApplicationRepository 94 WebhookRepoFn func() *automock.WebhookRepository 95 IntSysRepoFn func() *automock.IntegrationSystemRepository 96 LabelServiceFn func() *automock.LabelService 97 BundleServiceFn func() *automock.BundleService 98 UIDServiceFn func() *automock.UIDService 99 FormationServiceFn func() *automock.FormationService 100 Input model.ApplicationRegisterInput 101 ExpectedErr error 102 }{ 103 { 104 Name: "Success with scenarios label", 105 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 106 AppRepoFn: func() *automock.ApplicationRepository { 107 repo := &automock.ApplicationRepository{} 108 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 109 repo.On("Create", ctx, tnt, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return(nil).Once() 110 return repo 111 }, 112 WebhookRepoFn: func() *automock.WebhookRepository { 113 repo := &automock.WebhookRepository{} 114 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 115 return repo 116 }, 117 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 118 repo := &automock.IntegrationSystemRepository{} 119 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 120 return repo 121 }, 122 LabelServiceFn: func() *automock.LabelService { 123 svc := &automock.LabelService{} 124 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 125 return svc 126 }, 127 BundleServiceFn: func() *automock.BundleService { 128 svc := &automock.BundleService{} 129 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(nil).Once() 130 return svc 131 }, 132 UIDServiceFn: func() *automock.UIDService { 133 svc := &automock.UIDService{} 134 svc.On("Generate").Return(id) 135 return svc 136 }, 137 FormationServiceFn: func() *automock.FormationService { 138 svc := &automock.FormationService{} 139 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 140 return svc 141 }, 142 Input: applicationRegisterInputWithScenarios(), 143 ExpectedErr: nil, 144 }, 145 { 146 Name: "Returns success when listing existing applications returns empty applications", 147 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 148 AppRepoFn: func() *automock.ApplicationRepository { 149 repo := &automock.ApplicationRepository{} 150 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{}, nil).Once() 151 repo.On("Create", ctx, tnt, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return(nil).Once() 152 return repo 153 }, 154 WebhookRepoFn: func() *automock.WebhookRepository { 155 repo := &automock.WebhookRepository{} 156 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 157 return repo 158 }, 159 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 160 repo := &automock.IntegrationSystemRepository{} 161 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 162 return repo 163 }, 164 FormationServiceFn: func() *automock.FormationService { 165 svc := &automock.FormationService{} 166 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 167 return svc 168 }, 169 LabelServiceFn: func() *automock.LabelService { 170 svc := &automock.LabelService{} 171 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 172 return svc 173 }, 174 BundleServiceFn: func() *automock.BundleService { 175 svc := &automock.BundleService{} 176 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(nil).Once() 177 return svc 178 }, 179 UIDServiceFn: func() *automock.UIDService { 180 svc := &automock.UIDService{} 181 svc.On("Generate").Return(id) 182 return svc 183 }, 184 Input: applicationRegisterInputWithScenarios(), 185 ExpectedErr: nil, 186 }, 187 { 188 Name: "Returns success when listing existing applications returns application with different name", 189 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 190 AppRepoFn: func() *automock.ApplicationRepository { 191 repo := &automock.ApplicationRepository{} 192 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: modelInput.Name + "-test"}}, nil).Once() 193 repo.On("Create", ctx, tnt, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return(nil).Once() 194 return repo 195 }, 196 WebhookRepoFn: func() *automock.WebhookRepository { 197 repo := &automock.WebhookRepository{} 198 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 199 return repo 200 }, 201 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 202 repo := &automock.IntegrationSystemRepository{} 203 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 204 return repo 205 }, 206 FormationServiceFn: func() *automock.FormationService { 207 svc := &automock.FormationService{} 208 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 209 return svc 210 }, 211 LabelServiceFn: func() *automock.LabelService { 212 svc := &automock.LabelService{} 213 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 214 return svc 215 }, 216 BundleServiceFn: func() *automock.BundleService { 217 svc := &automock.BundleService{} 218 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(nil).Once() 219 return svc 220 }, 221 UIDServiceFn: func() *automock.UIDService { 222 svc := &automock.UIDService{} 223 svc.On("Generate").Return(id) 224 return svc 225 }, 226 Input: applicationRegisterInputWithScenarios(), 227 ExpectedErr: nil, 228 }, 229 { 230 Name: "Returns error when listing existing applications returns application with same name", 231 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 232 AppRepoFn: func() *automock.ApplicationRepository { 233 repo := &automock.ApplicationRepository{} 234 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: modelInput.Name}}, nil).Once() 235 return repo 236 }, 237 WebhookRepoFn: UnusedWebhookRepository, 238 IntSysRepoFn: UnusedIntegrationSystemRepository, 239 LabelServiceFn: UnusedLabelService, 240 BundleServiceFn: UnusedBundleService, 241 UIDServiceFn: UnusedUIDService, 242 FormationServiceFn: UnusedFormationService, 243 Input: applicationRegisterInputWithScenarios(), 244 ExpectedErr: apperrors.NewNotUniqueNameError(resource.Application), 245 }, 246 { 247 Name: "Returns success when listing existing applications returns application with different name and incoming name is already normalized", 248 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 249 AppRepoFn: func() *automock.ApplicationRepository { 250 repo := &automock.ApplicationRepository{} 251 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: normalizedModelInput.Name + "-test"}}, nil).Once() 252 repo.On("Create", ctx, tnt, mock.MatchedBy(normalizedAppModel.ApplicationMatcherFn)).Return(nil).Once() 253 return repo 254 }, 255 WebhookRepoFn: func() *automock.WebhookRepository { 256 repo := &automock.WebhookRepository{} 257 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 258 return repo 259 }, 260 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 261 repo := &automock.IntegrationSystemRepository{} 262 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 263 return repo 264 }, 265 LabelServiceFn: func() *automock.LabelService { 266 svc := &automock.LabelService{} 267 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, normalizedLabels).Return(nil).Once() 268 return svc 269 }, 270 BundleServiceFn: func() *automock.BundleService { 271 svc := &automock.BundleService{} 272 svc.On("CreateMultiple", ctx, resource.Application, id, normalizedModelInput.Bundles).Return(nil).Once() 273 return svc 274 }, 275 UIDServiceFn: func() *automock.UIDService { 276 svc := &automock.UIDService{} 277 svc.On("Generate").Return(id) 278 return svc 279 }, 280 FormationServiceFn: UnusedFormationService, 281 Input: normalizedModelInput, 282 ExpectedErr: nil, 283 }, 284 { 285 Name: "Returns error when listing existing applications returns application with same name and incoming name is already normalized", 286 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 287 AppRepoFn: func() *automock.ApplicationRepository { 288 repo := &automock.ApplicationRepository{} 289 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: normalizedModelInput.Name}}, nil).Once() 290 return repo 291 }, 292 WebhookRepoFn: UnusedWebhookRepository, 293 IntSysRepoFn: UnusedIntegrationSystemRepository, 294 LabelServiceFn: UnusedLabelService, 295 BundleServiceFn: UnusedBundleService, 296 UIDServiceFn: UnusedUIDService, 297 FormationServiceFn: UnusedFormationService, 298 Input: normalizedModelInput, 299 ExpectedErr: apperrors.NewNotUniqueNameError(resource.Application), 300 }, 301 { 302 Name: "Success when no labels provided", 303 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 304 AppRepoFn: func() *automock.ApplicationRepository { 305 repo := &automock.ApplicationRepository{} 306 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 307 repo.On("Create", ctx, tnt, mock.MatchedBy(applicationMatcher("test", nil))).Return(nil).Once() 308 return repo 309 }, 310 WebhookRepoFn: func() *automock.WebhookRepository { 311 repo := &automock.WebhookRepository{} 312 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 313 return repo 314 }, 315 IntSysRepoFn: UnusedIntegrationSystemRepository, 316 LabelServiceFn: func() *automock.LabelService { 317 svc := &automock.LabelService{} 318 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 319 return svc 320 }, 321 BundleServiceFn: UnusedBundleService, 322 UIDServiceFn: func() *automock.UIDService { 323 svc := &automock.UIDService{} 324 svc.On("Generate").Return(id) 325 return svc 326 }, 327 FormationServiceFn: UnusedFormationService, 328 Input: model.ApplicationRegisterInput{Name: "test", Labels: nilLabels}, 329 ExpectedErr: nil, 330 }, 331 { 332 Name: "Success when scenarios label provided", 333 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 334 AppRepoFn: func() *automock.ApplicationRepository { 335 repo := &automock.ApplicationRepository{} 336 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 337 repo.On("Create", ctx, tnt, mock.MatchedBy(applicationMatcher("test", nil))).Return(nil).Once() 338 return repo 339 }, 340 WebhookRepoFn: func() *automock.WebhookRepository { 341 repo := &automock.WebhookRepository{} 342 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 343 return repo 344 }, 345 IntSysRepoFn: UnusedIntegrationSystemRepository, 346 FormationServiceFn: UnusedFormationService, 347 LabelServiceFn: func() *automock.LabelService { 348 svc := &automock.LabelService{} 349 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 350 return svc 351 }, 352 BundleServiceFn: UnusedBundleService, 353 UIDServiceFn: func() *automock.UIDService { 354 svc := &automock.UIDService{} 355 svc.On("Generate").Return(id) 356 return svc 357 }, 358 Input: model.ApplicationRegisterInput{ 359 Name: "test", 360 Labels: labelsWithoutIntSys, 361 }, 362 ExpectedErr: nil, 363 }, 364 { 365 Name: "Returns error when application creation failed", 366 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 367 AppRepoFn: func() *automock.ApplicationRepository { 368 repo := &automock.ApplicationRepository{} 369 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 370 repo.On("Create", ctx, tnt, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return(testErr).Once() 371 return repo 372 }, 373 WebhookRepoFn: UnusedWebhookRepository, 374 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 375 repo := &automock.IntegrationSystemRepository{} 376 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 377 return repo 378 }, 379 LabelServiceFn: UnusedLabelService, 380 BundleServiceFn: UnusedBundleService, 381 UIDServiceFn: func() *automock.UIDService { 382 svc := &automock.UIDService{} 383 svc.On("Generate").Return(id).Once() 384 return svc 385 }, 386 FormationServiceFn: UnusedFormationService, 387 Input: applicationRegisterInputWithScenarios(), 388 ExpectedErr: testErr, 389 }, 390 { 391 Name: "Returns error when listing existing applications fails", 392 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 393 AppRepoFn: func() *automock.ApplicationRepository { 394 repo := &automock.ApplicationRepository{} 395 repo.On("ListAll", ctx, mock.Anything).Return(nil, testErr).Once() 396 return repo 397 }, 398 WebhookRepoFn: UnusedWebhookRepository, 399 IntSysRepoFn: UnusedIntegrationSystemRepository, 400 LabelServiceFn: UnusedLabelService, 401 BundleServiceFn: UnusedBundleService, 402 UIDServiceFn: UnusedUIDService, 403 FormationServiceFn: UnusedFormationService, 404 Input: applicationRegisterInputWithScenarios(), 405 ExpectedErr: testErr, 406 }, 407 { 408 Name: "Returns error when integration system doesn't exist", 409 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 410 AppRepoFn: func() *automock.ApplicationRepository { 411 repo := &automock.ApplicationRepository{} 412 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 413 return repo 414 }, 415 WebhookRepoFn: UnusedWebhookRepository, 416 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 417 repo := &automock.IntegrationSystemRepository{} 418 repo.On("Exists", ctx, intSysID).Return(false, nil).Once() 419 return repo 420 }, 421 LabelServiceFn: UnusedLabelService, 422 BundleServiceFn: UnusedBundleService, 423 UIDServiceFn: UnusedUIDService, 424 FormationServiceFn: UnusedFormationService, 425 Input: applicationRegisterInputWithScenarios(), 426 ExpectedErr: errors.New("Object not found"), 427 }, 428 { 429 Name: "Returns error when checking for integration system fails", 430 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 431 AppRepoFn: func() *automock.ApplicationRepository { 432 repo := &automock.ApplicationRepository{} 433 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 434 return repo 435 }, 436 WebhookRepoFn: UnusedWebhookRepository, 437 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 438 repo := &automock.IntegrationSystemRepository{} 439 repo.On("Exists", ctx, intSysID).Return(false, testErr).Once() 440 return repo 441 }, 442 LabelServiceFn: UnusedLabelService, 443 BundleServiceFn: UnusedBundleService, 444 UIDServiceFn: UnusedUIDService, 445 FormationServiceFn: UnusedFormationService, 446 Input: applicationRegisterInputWithScenarios(), 447 ExpectedErr: testErr, 448 }, 449 { 450 Name: "Returns error when creating bundles", 451 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 452 AppRepoFn: func() *automock.ApplicationRepository { 453 repo := &automock.ApplicationRepository{} 454 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 455 repo.On("Create", ctx, tnt, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return(nil).Once() 456 return repo 457 }, 458 WebhookRepoFn: func() *automock.WebhookRepository { 459 repo := &automock.WebhookRepository{} 460 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 461 return repo 462 }, 463 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 464 repo := &automock.IntegrationSystemRepository{} 465 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 466 return repo 467 }, 468 LabelServiceFn: func() *automock.LabelService { 469 svc := &automock.LabelService{} 470 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 471 return svc 472 }, 473 BundleServiceFn: func() *automock.BundleService { 474 svc := &automock.BundleService{} 475 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(testErr).Once() 476 return svc 477 }, 478 UIDServiceFn: func() *automock.UIDService { 479 svc := &automock.UIDService{} 480 svc.On("Generate").Return(id) 481 return svc 482 }, 483 FormationServiceFn: func() *automock.FormationService { 484 svc := &automock.FormationService{} 485 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 486 return svc 487 }, 488 Input: applicationRegisterInputWithScenarios(), 489 ExpectedErr: testErr, 490 }, 491 { 492 Name: "Returns error when failing during assigning formation", 493 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 494 AppRepoFn: func() *automock.ApplicationRepository { 495 repo := &automock.ApplicationRepository{} 496 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 497 repo.On("Create", ctx, tnt, mock.MatchedBy(applicationMatcher("test", nil))).Return(nil).Once() 498 return repo 499 }, 500 WebhookRepoFn: UnusedWebhookRepository, 501 IntSysRepoFn: UnusedIntegrationSystemRepository, 502 LabelServiceFn: func() *automock.LabelService { 503 svc := &automock.LabelService{} 504 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithScenarios).Return(nil).Once() 505 return svc 506 }, 507 BundleServiceFn: UnusedBundleService, 508 UIDServiceFn: func() *automock.UIDService { 509 svc := &automock.UIDService{} 510 svc.On("Generate").Return(id) 511 return svc 512 }, 513 FormationServiceFn: func() *automock.FormationService { 514 svc := &automock.FormationService{} 515 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, testErr).Once() 516 return svc 517 }, 518 Input: model.ApplicationRegisterInput{Name: "test", Labels: labelsWithScenarios}, 519 ExpectedErr: testErr, 520 }, 521 } 522 523 for _, testCase := range testCases { 524 t.Run(testCase.Name, func(t *testing.T) { 525 appNameNormalizer := testCase.AppNameNormalizer 526 appRepo := testCase.AppRepoFn() 527 webhookRepo := testCase.WebhookRepoFn() 528 labelSvc := testCase.LabelServiceFn() 529 uidSvc := testCase.UIDServiceFn() 530 intSysRepo := testCase.IntSysRepoFn() 531 bndlSvc := testCase.BundleServiceFn() 532 formationSvc := testCase.FormationServiceFn() 533 svc := application.NewService(appNameNormalizer, nil, appRepo, webhookRepo, nil, nil, intSysRepo, labelSvc, bndlSvc, uidSvc, formationSvc, "", nil) 534 svc.SetTimestampGen(func() time.Time { return timestamp }) 535 536 // WHEN 537 result, err := svc.Create(ctx, testCase.Input) 538 539 // THEN 540 assert.IsType(t, "string", result) 541 if testCase.ExpectedErr != nil { 542 require.NotNil(t, err) 543 assert.Contains(t, err.Error(), testCase.ExpectedErr.Error()) 544 } else { 545 require.Nil(t, err) 546 } 547 548 mock.AssertExpectationsForObjects(t, appRepo, webhookRepo, labelSvc, uidSvc, intSysRepo, bndlSvc, formationSvc) 549 }) 550 } 551 552 t.Run("Returns error on loading tenant", func(t *testing.T) { 553 svc := application.NewService(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 554 // WHEN 555 _, err := svc.Create(context.TODO(), model.ApplicationRegisterInput{}) 556 assert.True(t, apperrors.IsCannotReadTenant(err)) 557 }) 558 } 559 560 func TestService_CreateFromTemplate(t *testing.T) { 561 // GIVEN 562 timestamp := time.Now() 563 testErr := errors.New("Test error") 564 modelInput := applicationRegisterInputWithScenarios() 565 566 normalizedModelInput := model.ApplicationRegisterInput{ 567 Name: "mp-foo-bar-not", 568 Webhooks: []*model.WebhookInput{ 569 {URL: stringPtr("test.foo.com")}, 570 {URL: stringPtr("test.bar.com")}, 571 }, 572 573 Labels: map[string]interface{}{ 574 "label": "value", 575 }, 576 IntegrationSystemID: &intSysID, 577 } 578 normalizedModelInput.Bundles = modelInput.Bundles 579 580 labels := map[string]interface{}{ 581 "integrationSystemID": intSysID, 582 "label": "value", 583 "name": "mp-foo-bar-not", 584 "applicationType": "test-app-with-ppms", 585 "ppmsProductVersionId": "1", 586 } 587 normalizedLabels := map[string]interface{}{ 588 "integrationSystemID": intSysID, 589 "label": "value", 590 "name": "mp-foo-bar-not", 591 } 592 labelsWithoutIntSys := map[string]interface{}{ 593 "integrationSystemID": "", 594 "name": "mp-test", 595 } 596 var nilLabels map[string]interface{} 597 598 id := "foo" 599 appTemplteID := "test-app-template" 600 tnt := "tenant" 601 externalTnt := "external-tnt" 602 603 appFromTemplateModel := modelFromInput(modelInput, tnt, id, applicationFromTemplateMatcher(modelInput.Name, modelInput.Description, &appTemplteID)) 604 normalizedAppModel := modelFromInput(normalizedModelInput, tnt, id, applicationFromTemplateMatcher(normalizedModelInput.Name, normalizedModelInput.Description, &appTemplteID)) 605 606 ctx := context.TODO() 607 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 608 609 testCases := []struct { 610 Name string 611 AppNameNormalizer normalizer.Normalizator 612 AppRepoFn func() *automock.ApplicationRepository 613 WebhookRepoFn func() *automock.WebhookRepository 614 IntSysRepoFn func() *automock.IntegrationSystemRepository 615 LabelServiceFn func() *automock.LabelService 616 BundleServiceFn func() *automock.BundleService 617 UIDServiceFn func() *automock.UIDService 618 FormationServiceFn func() *automock.FormationService 619 Input model.ApplicationRegisterInput 620 ExpectedErr error 621 }{ 622 { 623 Name: "Success", 624 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 625 AppRepoFn: func() *automock.ApplicationRepository { 626 repo := &automock.ApplicationRepository{} 627 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 628 repo.On("Create", ctx, tnt, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return(nil).Once() 629 return repo 630 }, 631 WebhookRepoFn: func() *automock.WebhookRepository { 632 repo := &automock.WebhookRepository{} 633 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 634 return repo 635 }, 636 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 637 repo := &automock.IntegrationSystemRepository{} 638 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 639 return repo 640 }, 641 LabelServiceFn: func() *automock.LabelService { 642 svc := &automock.LabelService{} 643 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 644 return svc 645 }, 646 BundleServiceFn: func() *automock.BundleService { 647 svc := &automock.BundleService{} 648 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(nil).Once() 649 return svc 650 }, 651 UIDServiceFn: func() *automock.UIDService { 652 svc := &automock.UIDService{} 653 svc.On("Generate").Return(id) 654 return svc 655 }, 656 FormationServiceFn: func() *automock.FormationService { 657 svc := &automock.FormationService{} 658 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 659 return svc 660 }, 661 Input: applicationRegisterInputWithScenarios(), 662 ExpectedErr: nil, 663 }, 664 { 665 Name: "Returns success when listing existing applications returns empty applications", 666 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 667 AppRepoFn: func() *automock.ApplicationRepository { 668 repo := &automock.ApplicationRepository{} 669 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{}, nil).Once() 670 repo.On("Create", ctx, tnt, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return(nil).Once() 671 return repo 672 }, 673 WebhookRepoFn: func() *automock.WebhookRepository { 674 repo := &automock.WebhookRepository{} 675 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 676 return repo 677 }, 678 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 679 repo := &automock.IntegrationSystemRepository{} 680 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 681 return repo 682 }, 683 LabelServiceFn: func() *automock.LabelService { 684 svc := &automock.LabelService{} 685 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 686 return svc 687 }, 688 BundleServiceFn: func() *automock.BundleService { 689 svc := &automock.BundleService{} 690 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(nil).Once() 691 return svc 692 }, 693 UIDServiceFn: func() *automock.UIDService { 694 svc := &automock.UIDService{} 695 svc.On("Generate").Return(id) 696 return svc 697 }, 698 FormationServiceFn: func() *automock.FormationService { 699 svc := &automock.FormationService{} 700 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 701 return svc 702 }, 703 Input: applicationRegisterInputWithScenarios(), 704 ExpectedErr: nil, 705 }, 706 { 707 Name: "Returns success when listing existing applications returns application with different name", 708 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 709 AppRepoFn: func() *automock.ApplicationRepository { 710 repo := &automock.ApplicationRepository{} 711 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: modelInput.Name + "-test"}}, nil).Once() 712 repo.On("Create", ctx, tnt, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return(nil).Once() 713 return repo 714 }, 715 WebhookRepoFn: func() *automock.WebhookRepository { 716 repo := &automock.WebhookRepository{} 717 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 718 return repo 719 }, 720 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 721 repo := &automock.IntegrationSystemRepository{} 722 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 723 return repo 724 }, 725 LabelServiceFn: func() *automock.LabelService { 726 svc := &automock.LabelService{} 727 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 728 return svc 729 }, 730 BundleServiceFn: func() *automock.BundleService { 731 svc := &automock.BundleService{} 732 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(nil).Once() 733 return svc 734 }, 735 UIDServiceFn: func() *automock.UIDService { 736 svc := &automock.UIDService{} 737 svc.On("Generate").Return(id) 738 return svc 739 }, 740 FormationServiceFn: func() *automock.FormationService { 741 svc := &automock.FormationService{} 742 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 743 return svc 744 }, 745 Input: applicationRegisterInputWithScenarios(), 746 ExpectedErr: nil, 747 }, 748 { 749 Name: "Returns error when listing existing applications returns application with same name", 750 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 751 AppRepoFn: func() *automock.ApplicationRepository { 752 repo := &automock.ApplicationRepository{} 753 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: modelInput.Name}}, nil).Once() 754 return repo 755 }, 756 WebhookRepoFn: UnusedWebhookRepository, 757 IntSysRepoFn: UnusedIntegrationSystemRepository, 758 LabelServiceFn: UnusedLabelService, 759 BundleServiceFn: UnusedBundleService, 760 UIDServiceFn: UnusedUIDService, 761 FormationServiceFn: UnusedFormationService, 762 Input: applicationRegisterInputWithScenarios(), 763 ExpectedErr: apperrors.NewNotUniqueNameError(resource.Application), 764 }, 765 { 766 Name: "Returns success when listing existing applications returns application with different name and incoming name is already normalized", 767 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 768 AppRepoFn: func() *automock.ApplicationRepository { 769 repo := &automock.ApplicationRepository{} 770 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: normalizedModelInput.Name + "-test"}}, nil).Once() 771 repo.On("Create", ctx, tnt, mock.MatchedBy(normalizedAppModel.ApplicationMatcherFn)).Return(nil).Once() 772 return repo 773 }, 774 WebhookRepoFn: func() *automock.WebhookRepository { 775 repo := &automock.WebhookRepository{} 776 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 777 return repo 778 }, 779 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 780 repo := &automock.IntegrationSystemRepository{} 781 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 782 return repo 783 }, 784 LabelServiceFn: func() *automock.LabelService { 785 svc := &automock.LabelService{} 786 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, normalizedLabels).Return(nil).Once() 787 return svc 788 }, 789 BundleServiceFn: func() *automock.BundleService { 790 svc := &automock.BundleService{} 791 svc.On("CreateMultiple", ctx, resource.Application, id, normalizedModelInput.Bundles).Return(nil).Once() 792 return svc 793 }, 794 UIDServiceFn: func() *automock.UIDService { 795 svc := &automock.UIDService{} 796 svc.On("Generate").Return(id) 797 return svc 798 }, 799 FormationServiceFn: UnusedFormationService, 800 Input: normalizedModelInput, 801 ExpectedErr: nil, 802 }, 803 { 804 Name: "Returns error when listing existing applications returns application with same name and incoming name is already normalized", 805 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 806 AppRepoFn: func() *automock.ApplicationRepository { 807 repo := &automock.ApplicationRepository{} 808 repo.On("ListAll", ctx, mock.Anything).Return([]*model.Application{{Name: normalizedModelInput.Name}}, nil).Once() 809 return repo 810 }, 811 WebhookRepoFn: UnusedWebhookRepository, 812 IntSysRepoFn: UnusedIntegrationSystemRepository, 813 LabelServiceFn: UnusedLabelService, 814 BundleServiceFn: UnusedBundleService, 815 UIDServiceFn: UnusedUIDService, 816 FormationServiceFn: UnusedFormationService, 817 Input: normalizedModelInput, 818 ExpectedErr: apperrors.NewNotUniqueNameError(resource.Application), 819 }, 820 { 821 Name: "Success when no labels provided", 822 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 823 AppRepoFn: func() *automock.ApplicationRepository { 824 repo := &automock.ApplicationRepository{} 825 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 826 repo.On("Create", ctx, tnt, mock.MatchedBy(applicationMatcher("test", nil))).Return(nil).Once() 827 return repo 828 }, 829 WebhookRepoFn: func() *automock.WebhookRepository { 830 repo := &automock.WebhookRepository{} 831 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 832 return repo 833 }, 834 IntSysRepoFn: UnusedIntegrationSystemRepository, 835 LabelServiceFn: func() *automock.LabelService { 836 svc := &automock.LabelService{} 837 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 838 return svc 839 }, 840 BundleServiceFn: UnusedBundleService, 841 UIDServiceFn: func() *automock.UIDService { 842 svc := &automock.UIDService{} 843 svc.On("Generate").Return(id) 844 return svc 845 }, 846 FormationServiceFn: UnusedFormationService, 847 Input: model.ApplicationRegisterInput{Name: "test", Labels: nilLabels}, 848 ExpectedErr: nil, 849 }, 850 { 851 Name: "Returns error when application creation failed", 852 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 853 AppRepoFn: func() *automock.ApplicationRepository { 854 repo := &automock.ApplicationRepository{} 855 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 856 repo.On("Create", ctx, tnt, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return(testErr).Once() 857 return repo 858 }, 859 WebhookRepoFn: UnusedWebhookRepository, 860 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 861 repo := &automock.IntegrationSystemRepository{} 862 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 863 return repo 864 }, 865 LabelServiceFn: UnusedLabelService, 866 BundleServiceFn: UnusedBundleService, 867 UIDServiceFn: func() *automock.UIDService { 868 svc := &automock.UIDService{} 869 svc.On("Generate").Return(id).Once() 870 return svc 871 }, 872 FormationServiceFn: UnusedFormationService, 873 Input: applicationRegisterInputWithScenarios(), 874 ExpectedErr: testErr, 875 }, 876 { 877 Name: "Returns error when listing existing applications fails", 878 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 879 AppRepoFn: func() *automock.ApplicationRepository { 880 repo := &automock.ApplicationRepository{} 881 repo.On("ListAll", ctx, mock.Anything).Return(nil, testErr).Once() 882 return repo 883 }, 884 WebhookRepoFn: UnusedWebhookRepository, 885 IntSysRepoFn: UnusedIntegrationSystemRepository, 886 LabelServiceFn: UnusedLabelService, 887 BundleServiceFn: UnusedBundleService, 888 UIDServiceFn: UnusedUIDService, 889 FormationServiceFn: UnusedFormationService, 890 Input: applicationRegisterInputWithScenarios(), 891 ExpectedErr: testErr, 892 }, 893 { 894 Name: "Returns error when integration system doesn't exist", 895 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 896 AppRepoFn: func() *automock.ApplicationRepository { 897 repo := &automock.ApplicationRepository{} 898 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 899 return repo 900 }, 901 WebhookRepoFn: UnusedWebhookRepository, 902 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 903 repo := &automock.IntegrationSystemRepository{} 904 repo.On("Exists", ctx, intSysID).Return(false, nil).Once() 905 return repo 906 }, 907 LabelServiceFn: UnusedLabelService, 908 BundleServiceFn: UnusedBundleService, 909 UIDServiceFn: UnusedUIDService, 910 FormationServiceFn: UnusedFormationService, 911 Input: applicationRegisterInputWithScenarios(), 912 ExpectedErr: errors.New("Object not found"), 913 }, 914 { 915 Name: "Returns error when checking for integration system fails", 916 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 917 AppRepoFn: func() *automock.ApplicationRepository { 918 repo := &automock.ApplicationRepository{} 919 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 920 return repo 921 }, 922 WebhookRepoFn: UnusedWebhookRepository, 923 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 924 repo := &automock.IntegrationSystemRepository{} 925 repo.On("Exists", ctx, intSysID).Return(false, testErr).Once() 926 return repo 927 }, 928 LabelServiceFn: UnusedLabelService, 929 BundleServiceFn: UnusedBundleService, 930 UIDServiceFn: UnusedUIDService, 931 FormationServiceFn: UnusedFormationService, 932 Input: applicationRegisterInputWithScenarios(), 933 ExpectedErr: testErr, 934 }, 935 { 936 Name: "Returns error when creating bundles", 937 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 938 AppRepoFn: func() *automock.ApplicationRepository { 939 repo := &automock.ApplicationRepository{} 940 repo.On("ListAll", ctx, mock.Anything).Return(nil, nil).Once() 941 repo.On("Create", ctx, tnt, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return(nil).Once() 942 return repo 943 }, 944 WebhookRepoFn: func() *automock.WebhookRepository { 945 repo := &automock.WebhookRepository{} 946 repo.On("CreateMany", ctx, tnt, mock.Anything).Return(nil).Once() 947 return repo 948 }, 949 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 950 repo := &automock.IntegrationSystemRepository{} 951 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 952 return repo 953 }, 954 LabelServiceFn: func() *automock.LabelService { 955 svc := &automock.LabelService{} 956 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 957 return svc 958 }, 959 BundleServiceFn: func() *automock.BundleService { 960 svc := &automock.BundleService{} 961 svc.On("CreateMultiple", ctx, resource.Application, id, modelInput.Bundles).Return(testErr).Once() 962 return svc 963 }, 964 UIDServiceFn: func() *automock.UIDService { 965 svc := &automock.UIDService{} 966 svc.On("Generate").Return(id) 967 return svc 968 }, 969 FormationServiceFn: func() *automock.FormationService { 970 svc := &automock.FormationService{} 971 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 972 return svc 973 }, 974 Input: applicationRegisterInputWithScenarios(), 975 ExpectedErr: testErr, 976 }, 977 } 978 979 for _, testCase := range testCases { 980 t.Run(testCase.Name, func(t *testing.T) { 981 appNameNormalizer := testCase.AppNameNormalizer 982 appRepo := testCase.AppRepoFn() 983 webhookRepo := testCase.WebhookRepoFn() 984 labelSvc := testCase.LabelServiceFn() 985 uidSvc := testCase.UIDServiceFn() 986 intSysRepo := testCase.IntSysRepoFn() 987 bndlSvc := testCase.BundleServiceFn() 988 formationSvc := testCase.FormationServiceFn() 989 svc := application.NewService(appNameNormalizer, nil, appRepo, webhookRepo, nil, nil, intSysRepo, labelSvc, bndlSvc, uidSvc, formationSvc, "", nil) 990 svc.SetTimestampGen(func() time.Time { return timestamp }) 991 992 // WHEN 993 result, err := svc.CreateFromTemplate(ctx, testCase.Input, &appTemplteID) 994 995 // then 996 assert.IsType(t, "string", result) 997 if testCase.ExpectedErr != nil { 998 require.NotNil(t, err) 999 assert.Contains(t, err.Error(), testCase.ExpectedErr.Error()) 1000 } else { 1001 require.Nil(t, err) 1002 } 1003 1004 mock.AssertExpectationsForObjects(t, appRepo, intSysRepo, uidSvc, bndlSvc, formationSvc, webhookRepo, labelSvc) 1005 }) 1006 } 1007 1008 t.Run("Returns error on loading tenant", func(t *testing.T) { 1009 svc := application.NewService(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 1010 // WHEN 1011 _, err := svc.Create(context.TODO(), model.ApplicationRegisterInput{}) 1012 assert.True(t, apperrors.IsCannotReadTenant(err)) 1013 }) 1014 } 1015 1016 func TestService_Upsert_TrustedUpsert(t *testing.T) { 1017 // given 1018 timestamp := time.Now() 1019 testErr := errors.New("Test error") 1020 modelInput := applicationRegisterInputWithScenarios() 1021 1022 normalizedModelInput := model.ApplicationRegisterInput{ 1023 Name: "mp-foo-bar-not", 1024 Webhooks: []*model.WebhookInput{ 1025 {URL: stringPtr("test.foo.com")}, 1026 {URL: stringPtr("test.bar.com")}, 1027 }, 1028 1029 Labels: map[string]interface{}{ 1030 "label": "value", 1031 }, 1032 IntegrationSystemID: &intSysID, 1033 } 1034 normalizedModelInput.Bundles = modelInput.Bundles 1035 1036 labels := map[string]interface{}{ 1037 "integrationSystemID": intSysID, 1038 "label": "value", 1039 "name": "mp-foo-bar-not", 1040 "applicationType": "test-app-with-ppms", 1041 "ppmsProductVersionId": "1", 1042 } 1043 1044 labelsWithoutIntSys := map[string]interface{}{ 1045 "integrationSystemID": "", 1046 "name": "mp-test", 1047 } 1048 1049 labelsWithInvalidPpmsProductVersion := map[string]interface{}{ 1050 "integrationSystemID": intSysID, 1051 "label": "value", 1052 "name": "mp-foo-bar-not", 1053 "applicationType": "test-app-with-ppms", 1054 "ppmsProductVersionId": "2", 1055 } 1056 1057 var nilLabels map[string]interface{} 1058 1059 modelInputWithoutApplicationType := model.ApplicationRegisterInput{ 1060 Name: "foo.bar-not", 1061 Labels: map[string]interface{}{ 1062 "label": "value", 1063 "ppmsProductVersionId": "1", 1064 }, 1065 IntegrationSystemID: &intSysID, 1066 BaseURL: str.Ptr("http://test.com"), 1067 } 1068 1069 id := "foo" 1070 1071 tnt := "tenant" 1072 externalTnt := "external-tnt" 1073 1074 appModel := modelFromInput(modelInput, tnt, id, applicationMatcher(modelInput.Name, modelInput.Description)) 1075 1076 ctx := context.TODO() 1077 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 1078 1079 ordWebhookMapping := []application.ORDWebhookMapping{ 1080 { 1081 Type: "test-app", 1082 }, 1083 { 1084 Type: "test-app-with-ppms", 1085 PpmsProductVersions: []string{"1"}, 1086 }, 1087 } 1088 1089 testCases := []struct { 1090 Name string 1091 AppNameNormalizer normalizer.Normalizator 1092 AppRepoFn func(string) *automock.ApplicationRepository 1093 IntSysRepoFn func() *automock.IntegrationSystemRepository 1094 LabelServiceFn func() *automock.LabelService 1095 LabelRepoFn func() *automock.LabelRepository 1096 UIDServiceFn func() *automock.UIDService 1097 WebhookRepoFn func() *automock.WebhookRepository 1098 FormationServiceFn func() *automock.FormationService 1099 GetInput func() model.ApplicationRegisterInput 1100 OrdWebhookMapping []application.ORDWebhookMapping 1101 ExpectedErr error 1102 }{ 1103 { 1104 Name: "Success", 1105 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1106 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1107 repo := &automock.ApplicationRepository{} 1108 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1109 return repo 1110 }, 1111 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1112 repo := &automock.IntegrationSystemRepository{} 1113 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1114 return repo 1115 }, 1116 LabelServiceFn: func() *automock.LabelService { 1117 svc := &automock.LabelService{} 1118 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1119 return svc 1120 }, 1121 LabelRepoFn: func() *automock.LabelRepository { 1122 repo := &automock.LabelRepository{} 1123 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1124 return repo 1125 }, 1126 UIDServiceFn: func() *automock.UIDService { 1127 svc := &automock.UIDService{} 1128 svc.On("Generate").Return(id) 1129 return svc 1130 }, 1131 WebhookRepoFn: func() *automock.WebhookRepository { 1132 webhookRepo := &automock.WebhookRepository{} 1133 wh := &model.Webhook{ 1134 URL: stringPtr("test.foo.com"), 1135 ObjectID: id, 1136 } 1137 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return([]*model.Webhook{wh}, nil) 1138 webhookRepo.On("CreateMany", ctx, tnt, mock.AnythingOfType("[]*model.Webhook")).Return(nil) 1139 return webhookRepo 1140 }, 1141 FormationServiceFn: func() *automock.FormationService { 1142 svc := &automock.FormationService{} 1143 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1144 return svc 1145 }, 1146 OrdWebhookMapping: ordWebhookMapping, 1147 GetInput: func() model.ApplicationRegisterInput { 1148 return applicationRegisterInputWithScenarios() 1149 }, 1150 ExpectedErr: nil, 1151 }, 1152 { 1153 Name: "Success when no labels provided", 1154 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1155 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1156 repo := &automock.ApplicationRepository{} 1157 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(applicationMatcher("test", nil))).Return("foo", nil).Once() 1158 return repo 1159 }, 1160 IntSysRepoFn: UnusedIntegrationSystemRepository, 1161 LabelServiceFn: func() *automock.LabelService { 1162 svc := &automock.LabelService{} 1163 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 1164 return svc 1165 }, 1166 LabelRepoFn: UnusedLabelRepository, 1167 UIDServiceFn: func() *automock.UIDService { 1168 svc := &automock.UIDService{} 1169 svc.On("Generate").Return(id) 1170 return svc 1171 }, 1172 WebhookRepoFn: UnusedWebhookRepository, 1173 FormationServiceFn: UnusedFormationService, 1174 GetInput: func() model.ApplicationRegisterInput { 1175 return model.ApplicationRegisterInput{Name: "test", Labels: nilLabels} 1176 }, 1177 ExpectedErr: nil, 1178 }, 1179 { 1180 Name: "Success when scenarios label not provided", 1181 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1182 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1183 repo := &automock.ApplicationRepository{} 1184 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(applicationMatcher("test", nil))).Return("foo", nil).Once() 1185 return repo 1186 }, 1187 IntSysRepoFn: UnusedIntegrationSystemRepository, 1188 LabelServiceFn: func() *automock.LabelService { 1189 svc := &automock.LabelService{} 1190 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 1191 return svc 1192 }, 1193 LabelRepoFn: UnusedLabelRepository, 1194 UIDServiceFn: func() *automock.UIDService { 1195 svc := &automock.UIDService{} 1196 svc.On("Generate").Return(id) 1197 return svc 1198 }, 1199 WebhookRepoFn: UnusedWebhookRepository, 1200 FormationServiceFn: UnusedFormationService, 1201 GetInput: func() model.ApplicationRegisterInput { 1202 return model.ApplicationRegisterInput{ 1203 Name: "test", 1204 Labels: labelsWithoutIntSys, 1205 } 1206 }, 1207 ExpectedErr: nil, 1208 }, 1209 { 1210 Name: "Error when assigning formation", 1211 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1212 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1213 repo := &automock.ApplicationRepository{} 1214 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1215 return repo 1216 }, 1217 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1218 repo := &automock.IntegrationSystemRepository{} 1219 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1220 return repo 1221 }, 1222 LabelServiceFn: UnusedLabelService, 1223 LabelRepoFn: func() *automock.LabelRepository { 1224 repo := &automock.LabelRepository{} 1225 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1226 return repo 1227 }, 1228 UIDServiceFn: func() *automock.UIDService { 1229 svc := &automock.UIDService{} 1230 svc.On("Generate").Return(id) 1231 return svc 1232 }, 1233 WebhookRepoFn: UnusedWebhookRepository, 1234 FormationServiceFn: func() *automock.FormationService { 1235 svc := &automock.FormationService{} 1236 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, testErr).Once() 1237 return svc 1238 }, 1239 OrdWebhookMapping: ordWebhookMapping, 1240 GetInput: func() model.ApplicationRegisterInput { 1241 return applicationRegisterInputWithScenarios() 1242 }, 1243 ExpectedErr: testErr, 1244 }, 1245 { 1246 Name: "Returns error when listing webhooks", 1247 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1248 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1249 repo := &automock.ApplicationRepository{} 1250 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1251 return repo 1252 }, 1253 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1254 repo := &automock.IntegrationSystemRepository{} 1255 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1256 return repo 1257 }, 1258 LabelServiceFn: func() *automock.LabelService { 1259 svc := &automock.LabelService{} 1260 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1261 return svc 1262 }, 1263 LabelRepoFn: func() *automock.LabelRepository { 1264 repo := &automock.LabelRepository{} 1265 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1266 return repo 1267 }, 1268 UIDServiceFn: func() *automock.UIDService { 1269 svc := &automock.UIDService{} 1270 svc.On("Generate").Return(id) 1271 return svc 1272 }, 1273 WebhookRepoFn: func() *automock.WebhookRepository { 1274 webhookRepo := &automock.WebhookRepository{} 1275 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return(nil, testErr) 1276 return webhookRepo 1277 }, 1278 FormationServiceFn: func() *automock.FormationService { 1279 svc := &automock.FormationService{} 1280 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1281 return svc 1282 }, 1283 OrdWebhookMapping: ordWebhookMapping, 1284 GetInput: func() model.ApplicationRegisterInput { 1285 return applicationRegisterInputWithScenarios() 1286 }, 1287 ExpectedErr: testErr, 1288 }, 1289 { 1290 Name: "Returns error when creating webhooks", 1291 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1292 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1293 repo := &automock.ApplicationRepository{} 1294 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1295 return repo 1296 }, 1297 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1298 repo := &automock.IntegrationSystemRepository{} 1299 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1300 return repo 1301 }, 1302 LabelServiceFn: func() *automock.LabelService { 1303 svc := &automock.LabelService{} 1304 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1305 return svc 1306 }, 1307 LabelRepoFn: func() *automock.LabelRepository { 1308 repo := &automock.LabelRepository{} 1309 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1310 return repo 1311 }, 1312 UIDServiceFn: func() *automock.UIDService { 1313 svc := &automock.UIDService{} 1314 svc.On("Generate").Return(id) 1315 return svc 1316 }, 1317 WebhookRepoFn: func() *automock.WebhookRepository { 1318 webhookRepo := &automock.WebhookRepository{} 1319 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return([]*model.Webhook{}, nil) 1320 webhookRepo.On("CreateMany", ctx, tnt, mock.AnythingOfType("[]*model.Webhook")).Return(testErr) 1321 return webhookRepo 1322 }, 1323 FormationServiceFn: func() *automock.FormationService { 1324 svc := &automock.FormationService{} 1325 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1326 return svc 1327 }, 1328 OrdWebhookMapping: ordWebhookMapping, 1329 GetInput: func() model.ApplicationRegisterInput { 1330 return applicationRegisterInputWithScenarios() 1331 }, 1332 ExpectedErr: testErr, 1333 }, 1334 { 1335 Name: "Returns error when application upsert failed", 1336 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1337 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1338 repo := &automock.ApplicationRepository{} 1339 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("", testErr).Once() 1340 return repo 1341 }, 1342 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1343 repo := &automock.IntegrationSystemRepository{} 1344 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1345 return repo 1346 }, 1347 LabelServiceFn: UnusedLabelService, 1348 LabelRepoFn: UnusedLabelRepository, 1349 UIDServiceFn: func() *automock.UIDService { 1350 svc := &automock.UIDService{} 1351 svc.On("Generate").Return(id).Once() 1352 return svc 1353 }, 1354 WebhookRepoFn: UnusedWebhookRepository, 1355 FormationServiceFn: UnusedFormationService, 1356 GetInput: func() model.ApplicationRegisterInput { 1357 return applicationRegisterInputWithScenarios() 1358 }, 1359 ExpectedErr: testErr, 1360 }, 1361 { 1362 Name: "Returns error when integration system doesn't exist", 1363 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1364 AppRepoFn: func(_ string) *automock.ApplicationRepository { 1365 return &automock.ApplicationRepository{} 1366 }, 1367 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1368 repo := &automock.IntegrationSystemRepository{} 1369 repo.On("Exists", ctx, intSysID).Return(false, nil).Once() 1370 return repo 1371 }, 1372 LabelServiceFn: UnusedLabelService, 1373 LabelRepoFn: UnusedLabelRepository, 1374 UIDServiceFn: UnusedUIDService, 1375 WebhookRepoFn: UnusedWebhookRepository, 1376 FormationServiceFn: UnusedFormationService, 1377 GetInput: func() model.ApplicationRegisterInput { 1378 return applicationRegisterInputWithScenarios() 1379 }, 1380 ExpectedErr: errors.New("Object not found"), 1381 }, 1382 { 1383 Name: "Returns error when checking for integration system fails", 1384 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1385 AppRepoFn: func(_ string) *automock.ApplicationRepository { 1386 return &automock.ApplicationRepository{} 1387 }, 1388 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1389 repo := &automock.IntegrationSystemRepository{} 1390 repo.On("Exists", ctx, intSysID).Return(false, testErr).Once() 1391 return repo 1392 }, 1393 LabelServiceFn: UnusedLabelService, 1394 LabelRepoFn: UnusedLabelRepository, 1395 UIDServiceFn: UnusedUIDService, 1396 WebhookRepoFn: UnusedWebhookRepository, 1397 FormationServiceFn: UnusedFormationService, 1398 GetInput: func() model.ApplicationRegisterInput { 1399 return applicationRegisterInputWithScenarios() 1400 }, 1401 ExpectedErr: testErr, 1402 }, 1403 { 1404 Name: "Should not create webhooks when application type is missing from input labels", 1405 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1406 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1407 repo := &automock.ApplicationRepository{} 1408 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1409 return repo 1410 }, 1411 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1412 repo := &automock.IntegrationSystemRepository{} 1413 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1414 return repo 1415 }, 1416 LabelServiceFn: func() *automock.LabelService { 1417 svc := &automock.LabelService{} 1418 labels := map[string]interface{}{ 1419 "integrationSystemID": intSysID, 1420 "label": "value", 1421 "name": "mp-foo-bar-not", 1422 "ppmsProductVersionId": "1", 1423 } 1424 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1425 return svc 1426 }, 1427 LabelRepoFn: UnusedLabelRepository, 1428 UIDServiceFn: func() *automock.UIDService { 1429 svc := &automock.UIDService{} 1430 svc.On("Generate").Return(id).Once() 1431 return svc 1432 }, 1433 WebhookRepoFn: UnusedWebhookRepository, 1434 FormationServiceFn: UnusedFormationService, 1435 OrdWebhookMapping: ordWebhookMapping, 1436 GetInput: func() model.ApplicationRegisterInput { 1437 return modelInputWithoutApplicationType 1438 }, 1439 ExpectedErr: nil, 1440 }, 1441 { 1442 Name: "Should not create webhooks when baseURL is missing from input", 1443 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1444 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1445 repo := &automock.ApplicationRepository{} 1446 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1447 return repo 1448 }, 1449 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1450 repo := &automock.IntegrationSystemRepository{} 1451 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1452 return repo 1453 }, 1454 LabelServiceFn: func() *automock.LabelService { 1455 svc := &automock.LabelService{} 1456 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1457 return svc 1458 }, 1459 LabelRepoFn: func() *automock.LabelRepository { 1460 repo := &automock.LabelRepository{} 1461 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1462 return repo 1463 }, 1464 UIDServiceFn: func() *automock.UIDService { 1465 svc := &automock.UIDService{} 1466 svc.On("Generate").Return(id).Once() 1467 return svc 1468 }, 1469 WebhookRepoFn: UnusedWebhookRepository, 1470 FormationServiceFn: func() *automock.FormationService { 1471 svc := &automock.FormationService{} 1472 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1473 return svc 1474 }, 1475 OrdWebhookMapping: ordWebhookMapping, 1476 GetInput: func() model.ApplicationRegisterInput { 1477 modelInputWithoutBaseURL := applicationRegisterInputWithScenarios() 1478 modelInputWithoutBaseURL.BaseURL = str.Ptr("") 1479 return modelInputWithoutBaseURL 1480 }, 1481 ExpectedErr: nil, 1482 }, 1483 { 1484 Name: "Should not create webhooks when baseURL is invalid", 1485 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1486 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1487 repo := &automock.ApplicationRepository{} 1488 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1489 return repo 1490 }, 1491 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1492 repo := &automock.IntegrationSystemRepository{} 1493 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1494 return repo 1495 }, 1496 LabelServiceFn: func() *automock.LabelService { 1497 svc := &automock.LabelService{} 1498 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1499 return svc 1500 }, 1501 LabelRepoFn: func() *automock.LabelRepository { 1502 repo := &automock.LabelRepository{} 1503 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1504 return repo 1505 }, 1506 UIDServiceFn: func() *automock.UIDService { 1507 svc := &automock.UIDService{} 1508 svc.On("Generate").Return(id).Once() 1509 return svc 1510 }, 1511 WebhookRepoFn: UnusedWebhookRepository, 1512 FormationServiceFn: func() *automock.FormationService { 1513 svc := &automock.FormationService{} 1514 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1515 return svc 1516 }, 1517 OrdWebhookMapping: ordWebhookMapping, 1518 GetInput: func() model.ApplicationRegisterInput { 1519 modelInputWithInvalidBaseURL := applicationRegisterInputWithScenarios() 1520 modelInputWithInvalidBaseURL.BaseURL = str.Ptr("123://localhost") 1521 return modelInputWithInvalidBaseURL 1522 }, 1523 ExpectedErr: nil, 1524 }, 1525 { 1526 Name: "Should not create webhooks when ppmsProductVersion is present in input but is not in configuration", 1527 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1528 AppRepoFn: func(upsertMethodName string) *automock.ApplicationRepository { 1529 repo := &automock.ApplicationRepository{} 1530 repo.On(upsertMethodName, ctx, mock.Anything, mock.MatchedBy(appModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1531 return repo 1532 }, 1533 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1534 repo := &automock.IntegrationSystemRepository{} 1535 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1536 return repo 1537 }, 1538 LabelServiceFn: func() *automock.LabelService { 1539 svc := &automock.LabelService{} 1540 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithInvalidPpmsProductVersion).Return(nil).Once() 1541 return svc 1542 }, 1543 LabelRepoFn: func() *automock.LabelRepository { 1544 repo := &automock.LabelRepository{} 1545 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1546 return repo 1547 }, 1548 UIDServiceFn: func() *automock.UIDService { 1549 svc := &automock.UIDService{} 1550 svc.On("Generate").Return(id).Once() 1551 return svc 1552 }, 1553 WebhookRepoFn: UnusedWebhookRepository, 1554 FormationServiceFn: func() *automock.FormationService { 1555 svc := &automock.FormationService{} 1556 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1557 return svc 1558 }, 1559 OrdWebhookMapping: ordWebhookMapping, 1560 GetInput: func() model.ApplicationRegisterInput { 1561 modelInputWithInvalidPpmsProductVersion := applicationRegisterInputWithScenarios() 1562 modelInputWithInvalidPpmsProductVersion.Labels["ppmsProductVersionId"] = "2" 1563 modelInputWithInvalidPpmsProductVersion.BaseURL = str.Ptr("123://localhost") 1564 return modelInputWithInvalidPpmsProductVersion 1565 }, 1566 ExpectedErr: nil, 1567 }, 1568 } 1569 1570 for _, testCase := range testCases { 1571 t.Run(testCase.Name+"_Upsert", func(t *testing.T) { 1572 appNameNormalizer := testCase.AppNameNormalizer 1573 appRepo := testCase.AppRepoFn("Upsert") 1574 labelSvc := testCase.LabelServiceFn() 1575 labelRepo := testCase.LabelRepoFn() 1576 uidSvc := testCase.UIDServiceFn() 1577 intSysRepo := testCase.IntSysRepoFn() 1578 webhookRepo := testCase.WebhookRepoFn() 1579 formationService := testCase.FormationServiceFn() 1580 svc := application.NewService(appNameNormalizer, nil, appRepo, webhookRepo, nil, labelRepo, intSysRepo, labelSvc, nil, uidSvc, formationService, "", testCase.OrdWebhookMapping) 1581 svc.SetTimestampGen(func() time.Time { return timestamp }) 1582 1583 // when 1584 err := svc.Upsert(ctx, testCase.GetInput()) 1585 1586 // then 1587 if testCase.ExpectedErr != nil { 1588 require.NotNil(t, err) 1589 assert.Contains(t, err.Error(), testCase.ExpectedErr.Error()) 1590 } else { 1591 require.Nil(t, err) 1592 } 1593 1594 mock.AssertExpectationsForObjects(t, appRepo, labelSvc, labelRepo, uidSvc, intSysRepo, webhookRepo, formationService) 1595 }) 1596 1597 t.Run(testCase.Name+"_TrustedUpsert", func(t *testing.T) { 1598 appNameNormalizer := testCase.AppNameNormalizer 1599 appRepo := testCase.AppRepoFn("TrustedUpsert") 1600 labelSvc := testCase.LabelServiceFn() 1601 labelRepo := testCase.LabelRepoFn() 1602 uidSvc := testCase.UIDServiceFn() 1603 intSysRepo := testCase.IntSysRepoFn() 1604 webhookRepo := testCase.WebhookRepoFn() 1605 formationService := testCase.FormationServiceFn() 1606 svc := application.NewService(appNameNormalizer, nil, appRepo, webhookRepo, nil, labelRepo, intSysRepo, labelSvc, nil, uidSvc, formationService, "", testCase.OrdWebhookMapping) 1607 svc.SetTimestampGen(func() time.Time { return timestamp }) 1608 1609 // when 1610 err := svc.TrustedUpsert(ctx, testCase.GetInput()) 1611 1612 // then 1613 if testCase.ExpectedErr != nil { 1614 require.NotNil(t, err) 1615 assert.Contains(t, err.Error(), testCase.ExpectedErr.Error()) 1616 } else { 1617 require.Nil(t, err) 1618 } 1619 1620 mock.AssertExpectationsForObjects(t, appRepo, labelSvc, labelRepo, uidSvc, intSysRepo, webhookRepo, formationService) 1621 }) 1622 } 1623 1624 t.Run("Returns error on loading tenant", func(t *testing.T) { 1625 svc := application.NewService(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 1626 // when 1627 _, err := svc.Create(context.TODO(), model.ApplicationRegisterInput{}) 1628 assert.True(t, apperrors.IsCannotReadTenant(err)) 1629 }) 1630 } 1631 1632 func TestService_TrustedUpsertFromTemplate(t *testing.T) { 1633 // given 1634 timestamp := time.Now() 1635 testErr := errors.New("Test error") 1636 modelInput := applicationRegisterInputWithScenarios() 1637 1638 normalizedModelInput := model.ApplicationRegisterInput{ 1639 Name: "mp-foo-bar-not", 1640 Webhooks: []*model.WebhookInput{ 1641 {URL: stringPtr("test.foo.com")}, 1642 {URL: stringPtr("test.bar.com")}, 1643 }, 1644 1645 Labels: map[string]interface{}{ 1646 "label": "value", 1647 }, 1648 IntegrationSystemID: &intSysID, 1649 } 1650 normalizedModelInput.Bundles = modelInput.Bundles 1651 1652 labels := map[string]interface{}{ 1653 "integrationSystemID": intSysID, 1654 "label": "value", 1655 "name": "mp-foo-bar-not", 1656 "applicationType": "test-app-with-ppms", 1657 "ppmsProductVersionId": "1", 1658 } 1659 labelsWithoutIntSys := map[string]interface{}{ 1660 "integrationSystemID": "", 1661 "name": "mp-test", 1662 } 1663 var nilLabels map[string]interface{} 1664 1665 id := "foo" 1666 1667 tnt := "tenant" 1668 externalTnt := "external-tnt" 1669 appTemplteID := "test-app-template" 1670 1671 ordWebhookMapping := []application.ORDWebhookMapping{ 1672 { 1673 Type: "test-app", 1674 }, 1675 { 1676 Type: "test-app-with-ppms", 1677 PpmsProductVersions: []string{"1"}, 1678 }, 1679 } 1680 1681 appFromTemplateModel := modelFromInput(modelInput, tnt, id, applicationFromTemplateMatcher(modelInput.Name, modelInput.Description, &appTemplteID)) 1682 1683 ctx := context.TODO() 1684 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 1685 1686 testCases := []struct { 1687 Name string 1688 AppNameNormalizer normalizer.Normalizator 1689 AppRepoFn func() *automock.ApplicationRepository 1690 IntSysRepoFn func() *automock.IntegrationSystemRepository 1691 LabelServiceFn func() *automock.LabelService 1692 LabelRepoFn func() *automock.LabelRepository 1693 UIDServiceFn func() *automock.UIDService 1694 WebhookRepoFn func() *automock.WebhookRepository 1695 FormationServiceFn func() *automock.FormationService 1696 Input model.ApplicationRegisterInput 1697 OrdWebhookMapping []application.ORDWebhookMapping 1698 ExpectedErr error 1699 }{ 1700 { 1701 Name: "Success", 1702 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1703 AppRepoFn: func() *automock.ApplicationRepository { 1704 repo := &automock.ApplicationRepository{} 1705 repo.On("TrustedUpsert", ctx, mock.Anything, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1706 return repo 1707 }, 1708 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1709 repo := &automock.IntegrationSystemRepository{} 1710 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1711 return repo 1712 }, 1713 LabelServiceFn: func() *automock.LabelService { 1714 svc := &automock.LabelService{} 1715 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1716 return svc 1717 }, 1718 LabelRepoFn: func() *automock.LabelRepository { 1719 repo := &automock.LabelRepository{} 1720 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1721 return repo 1722 }, 1723 UIDServiceFn: func() *automock.UIDService { 1724 svc := &automock.UIDService{} 1725 svc.On("Generate").Return(id) 1726 return svc 1727 }, 1728 WebhookRepoFn: func() *automock.WebhookRepository { 1729 wh := &model.Webhook{ 1730 URL: stringPtr("test.foo.com"), 1731 ObjectID: id, 1732 } 1733 webhookRepo := &automock.WebhookRepository{} 1734 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return([]*model.Webhook{wh}, nil) 1735 webhookRepo.On("CreateMany", ctx, tnt, mock.AnythingOfType("[]*model.Webhook")).Return(nil) 1736 return webhookRepo 1737 }, 1738 FormationServiceFn: func() *automock.FormationService { 1739 svc := &automock.FormationService{} 1740 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1741 return svc 1742 }, 1743 OrdWebhookMapping: ordWebhookMapping, 1744 Input: applicationRegisterInputWithScenarios(), 1745 ExpectedErr: nil, 1746 }, 1747 { 1748 Name: "Success when no labels provided", 1749 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1750 AppRepoFn: func() *automock.ApplicationRepository { 1751 repo := &automock.ApplicationRepository{} 1752 repo.On("TrustedUpsert", ctx, mock.Anything, mock.MatchedBy(applicationMatcher("test", nil))).Return("foo", nil).Once() 1753 return repo 1754 }, 1755 IntSysRepoFn: UnusedIntegrationSystemRepository, 1756 LabelServiceFn: func() *automock.LabelService { 1757 svc := &automock.LabelService{} 1758 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 1759 return svc 1760 }, 1761 LabelRepoFn: UnusedLabelRepository, 1762 UIDServiceFn: func() *automock.UIDService { 1763 svc := &automock.UIDService{} 1764 svc.On("Generate").Return(id) 1765 return svc 1766 }, 1767 WebhookRepoFn: UnusedWebhookRepository, 1768 FormationServiceFn: UnusedFormationService, 1769 Input: model.ApplicationRegisterInput{Name: "test", Labels: nilLabels}, 1770 ExpectedErr: nil, 1771 }, 1772 { 1773 Name: "Success when scenarios label is not provided", 1774 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1775 AppRepoFn: func() *automock.ApplicationRepository { 1776 repo := &automock.ApplicationRepository{} 1777 repo.On("TrustedUpsert", ctx, mock.Anything, mock.MatchedBy(applicationMatcher("test", nil))).Return("foo", nil).Once() 1778 return repo 1779 }, 1780 IntSysRepoFn: UnusedIntegrationSystemRepository, 1781 LabelServiceFn: func() *automock.LabelService { 1782 svc := &automock.LabelService{} 1783 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labelsWithoutIntSys).Return(nil).Once() 1784 return svc 1785 }, 1786 LabelRepoFn: UnusedLabelRepository, 1787 UIDServiceFn: func() *automock.UIDService { 1788 svc := &automock.UIDService{} 1789 svc.On("Generate").Return(id) 1790 return svc 1791 }, 1792 WebhookRepoFn: UnusedWebhookRepository, 1793 FormationServiceFn: func() *automock.FormationService { 1794 svc := &automock.FormationService{} 1795 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1796 return svc 1797 }, 1798 Input: model.ApplicationRegisterInput{ 1799 Name: "test", 1800 Labels: labelsWithoutIntSys, 1801 }, 1802 ExpectedErr: nil, 1803 }, 1804 { 1805 Name: "Returns error when listing webhooks", 1806 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1807 AppRepoFn: func() *automock.ApplicationRepository { 1808 repo := &automock.ApplicationRepository{} 1809 repo.On("TrustedUpsert", ctx, mock.Anything, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1810 return repo 1811 }, 1812 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1813 repo := &automock.IntegrationSystemRepository{} 1814 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1815 return repo 1816 }, 1817 LabelServiceFn: func() *automock.LabelService { 1818 svc := &automock.LabelService{} 1819 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, labels).Return(nil).Once() 1820 return svc 1821 }, 1822 LabelRepoFn: func() *automock.LabelRepository { 1823 repo := &automock.LabelRepository{} 1824 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.ApplicationLabel, "")).Once() 1825 return repo 1826 }, 1827 UIDServiceFn: func() *automock.UIDService { 1828 svc := &automock.UIDService{} 1829 svc.On("Generate").Return(id) 1830 return svc 1831 }, 1832 WebhookRepoFn: func() *automock.WebhookRepository { 1833 webhookRepo := &automock.WebhookRepository{} 1834 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return(nil, testErr) 1835 return webhookRepo 1836 }, 1837 FormationServiceFn: func() *automock.FormationService { 1838 svc := &automock.FormationService{} 1839 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1840 return svc 1841 }, 1842 OrdWebhookMapping: ordWebhookMapping, 1843 Input: modelInput, 1844 ExpectedErr: testErr, 1845 }, 1846 { 1847 Name: "Returns error when creating webhooks", 1848 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1849 AppRepoFn: func() *automock.ApplicationRepository { 1850 repo := &automock.ApplicationRepository{} 1851 repo.On("TrustedUpsert", ctx, mock.Anything, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return("foo", nil).Once() 1852 return repo 1853 }, 1854 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1855 repo := &automock.IntegrationSystemRepository{} 1856 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1857 return repo 1858 }, 1859 LabelServiceFn: func() *automock.LabelService { 1860 svc := &automock.LabelService{} 1861 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, id, map[string]interface{}{ 1862 "integrationSystemID": intSysID, 1863 "label": "value", 1864 "name": "mp-foo-bar-not", 1865 "applicationType": "test-app", 1866 }).Return(nil).Once() 1867 return svc 1868 }, 1869 LabelRepoFn: UnusedLabelRepository, 1870 UIDServiceFn: func() *automock.UIDService { 1871 svc := &automock.UIDService{} 1872 svc.On("Generate").Return(id) 1873 return svc 1874 }, 1875 WebhookRepoFn: func() *automock.WebhookRepository { 1876 webhookRepo := &automock.WebhookRepository{} 1877 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return([]*model.Webhook{}, nil) 1878 webhookRepo.On("CreateMany", ctx, tnt, mock.AnythingOfType("[]*model.Webhook")).Return(testErr) 1879 return webhookRepo 1880 }, 1881 FormationServiceFn: UnusedFormationService, 1882 OrdWebhookMapping: ordWebhookMapping, 1883 Input: model.ApplicationRegisterInput{ 1884 Name: "foo.bar-not", 1885 Labels: map[string]interface{}{ 1886 "label": "value", 1887 "applicationType": "test-app", 1888 }, 1889 IntegrationSystemID: &intSysID, 1890 BaseURL: str.Ptr("http://localhost.com"), 1891 }, 1892 ExpectedErr: testErr, 1893 }, 1894 { 1895 Name: "Returns error when application trusted upsert failed", 1896 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1897 AppRepoFn: func() *automock.ApplicationRepository { 1898 repo := &automock.ApplicationRepository{} 1899 repo.On("TrustedUpsert", ctx, mock.Anything, mock.MatchedBy(appFromTemplateModel.ApplicationMatcherFn)).Return("", testErr).Once() 1900 return repo 1901 }, 1902 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1903 repo := &automock.IntegrationSystemRepository{} 1904 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 1905 return repo 1906 }, 1907 LabelServiceFn: UnusedLabelService, 1908 LabelRepoFn: UnusedLabelRepository, 1909 UIDServiceFn: func() *automock.UIDService { 1910 svc := &automock.UIDService{} 1911 svc.On("Generate").Return(id).Once() 1912 return svc 1913 }, 1914 FormationServiceFn: func() *automock.FormationService { 1915 svc := &automock.FormationService{} 1916 svc.On("AssignFormation", ctx, tnt, id, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 1917 return svc 1918 }, 1919 WebhookRepoFn: UnusedWebhookRepository, 1920 Input: applicationRegisterInputWithScenarios(), 1921 ExpectedErr: testErr, 1922 }, 1923 { 1924 Name: "Returns error when integration system doesn't exist", 1925 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1926 AppRepoFn: func() *automock.ApplicationRepository { 1927 return &automock.ApplicationRepository{} 1928 }, 1929 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1930 repo := &automock.IntegrationSystemRepository{} 1931 repo.On("Exists", ctx, intSysID).Return(false, nil).Once() 1932 return repo 1933 }, 1934 LabelServiceFn: UnusedLabelService, 1935 LabelRepoFn: UnusedLabelRepository, 1936 UIDServiceFn: UnusedUIDService, 1937 WebhookRepoFn: UnusedWebhookRepository, 1938 FormationServiceFn: UnusedFormationService, 1939 Input: applicationRegisterInputWithScenarios(), 1940 ExpectedErr: errors.New("Object not found"), 1941 }, 1942 { 1943 Name: "Returns error when checking for integration system fails", 1944 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 1945 AppRepoFn: func() *automock.ApplicationRepository { 1946 return &automock.ApplicationRepository{} 1947 }, 1948 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 1949 repo := &automock.IntegrationSystemRepository{} 1950 repo.On("Exists", ctx, intSysID).Return(false, testErr).Once() 1951 return repo 1952 }, 1953 LabelServiceFn: UnusedLabelService, 1954 LabelRepoFn: UnusedLabelRepository, 1955 UIDServiceFn: UnusedUIDService, 1956 WebhookRepoFn: UnusedWebhookRepository, 1957 FormationServiceFn: UnusedFormationService, 1958 Input: applicationRegisterInputWithScenarios(), 1959 ExpectedErr: testErr, 1960 }, 1961 } 1962 1963 for _, testCase := range testCases { 1964 t.Run(testCase.Name, func(t *testing.T) { 1965 appNameNormalizer := testCase.AppNameNormalizer 1966 appRepo := testCase.AppRepoFn() 1967 labelSvc := testCase.LabelServiceFn() 1968 labelRepo := testCase.LabelRepoFn() 1969 uidSvc := testCase.UIDServiceFn() 1970 intSysRepo := testCase.IntSysRepoFn() 1971 webhookRepo := testCase.WebhookRepoFn() 1972 formationService := testCase.FormationServiceFn() 1973 svc := application.NewService(appNameNormalizer, nil, appRepo, webhookRepo, nil, labelRepo, intSysRepo, labelSvc, nil, uidSvc, formationService, "", testCase.OrdWebhookMapping) 1974 svc.SetTimestampGen(func() time.Time { return timestamp }) 1975 1976 // when 1977 err := svc.TrustedUpsertFromTemplate(ctx, testCase.Input, &appTemplteID) 1978 1979 // then 1980 if testCase.ExpectedErr != nil { 1981 require.NotNil(t, err) 1982 assert.Contains(t, err.Error(), testCase.ExpectedErr.Error()) 1983 } else { 1984 require.Nil(t, err) 1985 } 1986 1987 mock.AssertExpectationsForObjects(t, appRepo, labelSvc, labelRepo, uidSvc, intSysRepo, webhookRepo) 1988 }) 1989 } 1990 1991 t.Run("Returns error on loading tenant", func(t *testing.T) { 1992 svc := application.NewService(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 1993 // when 1994 _, err := svc.Create(context.TODO(), model.ApplicationRegisterInput{}) 1995 assert.True(t, apperrors.IsCannotReadTenant(err)) 1996 }) 1997 } 1998 1999 func TestService_Update(t *testing.T) { 2000 // GIVEN 2001 testErr := errors.New("Test error") 2002 2003 id := "foo" 2004 tnt := "tenant" 2005 externalTnt := "external-tnt" 2006 conditionTimestamp := time.Now() 2007 timestampGenFunc := func() time.Time { return conditionTimestamp } 2008 2009 var updateInput model.ApplicationUpdateInput 2010 var applicationModelBefore *model.Application 2011 var applicationModelAfter *model.Application 2012 var intSysLabel *model.LabelInput 2013 var nameLabel *model.LabelInput 2014 var updateInputStatusOnly model.ApplicationUpdateInput 2015 var applicationModelAfterStatusUpdate *model.Application 2016 2017 appTypeLabel := &model.Label{ 2018 Key: "applicationType", 2019 Value: "test-app", 2020 } 2021 ppmsVersionIDLabel := &model.Label{ 2022 Key: "ppmsProductVersionId", 2023 Value: "1", 2024 } 2025 ordWebhookMapping := []application.ORDWebhookMapping{ 2026 { 2027 Type: "test-app", 2028 PpmsProductVersions: []string{"1"}, 2029 SubdomainSuffix: "-test", 2030 }, 2031 } 2032 2033 ctx := context.TODO() 2034 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 2035 2036 resetModels := func() { 2037 appName := "initialn" 2038 initialDescrription := "initald" 2039 initialURL := "initialu" 2040 updatedDescription := "updatedd" 2041 updatedHealthCheckURL := "updatedhcu" 2042 updatedBaseURL := "updatedbu" 2043 updatedApplicationNamespace := "updatedappns" 2044 updateInput = fixModelApplicationUpdateInput(appName, updatedDescription, updatedHealthCheckURL, updatedBaseURL, updatedApplicationNamespace, model.ApplicationStatusConditionConnected) 2045 applicationModelBefore = fixModelApplicationWithAllUpdatableFields(id, appName, initialDescrription, initialURL, nil, nil, model.ApplicationStatusConditionConnected, conditionTimestamp) 2046 applicationModelAfter = fixModelApplicationWithAllUpdatableFields(id, appName, updatedDescription, updatedHealthCheckURL, &updatedBaseURL, &updatedApplicationNamespace, model.ApplicationStatusConditionConnected, conditionTimestamp) 2047 intSysLabel = fixLabelInput("integrationSystemID", intSysID, id, model.ApplicationLabelableObject) 2048 intSysLabel.Version = 0 2049 nameLabel = fixLabelInput("name", "mp-"+appName, id, model.ApplicationLabelableObject) 2050 updateInputStatusOnly = fixModelApplicationUpdateInputStatus(model.ApplicationStatusConditionConnected) 2051 applicationModelAfterStatusUpdate = fixModelApplicationWithAllUpdatableFields(id, appName, initialDescrription, initialURL, nil, nil, model.ApplicationStatusConditionConnected, conditionTimestamp) 2052 } 2053 2054 resetModels() 2055 2056 testCases := []struct { 2057 Name string 2058 AppNameNormalizer normalizer.Normalizator 2059 AppRepoFn func() *automock.ApplicationRepository 2060 IntSysRepoFn func() *automock.IntegrationSystemRepository 2061 LabelSvcFn func() *automock.LabelService 2062 WebhookRepoFn func() *automock.WebhookRepository 2063 UIDServiceFn func() *automock.UIDService 2064 Input model.ApplicationUpdateInput 2065 InputID string 2066 ORDWebhookMapping []application.ORDWebhookMapping 2067 ExpectedErrMessage string 2068 }{ 2069 { 2070 Name: "Success", 2071 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2072 AppRepoFn: func() *automock.ApplicationRepository { 2073 repo := &automock.ApplicationRepository{} 2074 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2075 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2076 repo.On("Exists", ctx, tnt, id).Return(true, nil).Twice() 2077 return repo 2078 }, 2079 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2080 repo := &automock.IntegrationSystemRepository{} 2081 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2082 return repo 2083 }, 2084 LabelSvcFn: func() *automock.LabelService { 2085 svc := &automock.LabelService{} 2086 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(nil).Once() 2087 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2088 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(appTypeLabel, nil).Once() 2089 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "ppmsProductVersionId").Return(ppmsVersionIDLabel, nil).Once() 2090 return svc 2091 }, 2092 WebhookRepoFn: func() *automock.WebhookRepository { 2093 webhookRepo := &automock.WebhookRepository{} 2094 wh := &model.Webhook{ 2095 URL: stringPtr("test.foo.com"), 2096 ObjectID: id, 2097 } 2098 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return([]*model.Webhook{wh}, nil) 2099 webhookRepo.On("CreateMany", ctx, tnt, mock.AnythingOfType("[]*model.Webhook")).Return(nil) 2100 return webhookRepo 2101 }, 2102 UIDServiceFn: func() *automock.UIDService { 2103 svc := &automock.UIDService{} 2104 svc.On("Generate").Return(id) 2105 return svc 2106 }, 2107 InputID: "foo", 2108 ORDWebhookMapping: ordWebhookMapping, 2109 Input: updateInput, 2110 ExpectedErrMessage: "", 2111 }, 2112 { 2113 Name: "Success Status Condition Update", 2114 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2115 AppRepoFn: func() *automock.ApplicationRepository { 2116 repo := &automock.ApplicationRepository{} 2117 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2118 repo.On("Update", ctx, tnt, applicationModelAfterStatusUpdate).Return(nil).Once() 2119 repo.On("Exists", ctx, tnt, id).Return(true, nil).Once() 2120 return repo 2121 }, 2122 IntSysRepoFn: UnusedIntegrationSystemRepository, 2123 LabelSvcFn: func() *automock.LabelService { 2124 svc := &automock.LabelService{} 2125 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2126 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(appTypeLabel, nil).Once() 2127 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "ppmsProductVersionId").Return(ppmsVersionIDLabel, nil).Once() 2128 return svc 2129 }, 2130 WebhookRepoFn: UnusedWebhookRepository, 2131 UIDServiceFn: UnusedUIDService, 2132 InputID: "foo", 2133 Input: updateInputStatusOnly, 2134 ExpectedErrMessage: "", 2135 }, 2136 { 2137 Name: "Returns error when application update failed", 2138 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2139 AppRepoFn: func() *automock.ApplicationRepository { 2140 repo := &automock.ApplicationRepository{} 2141 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2142 repo.On("Update", ctx, tnt, applicationModelAfter).Return(testErr).Once() 2143 return repo 2144 }, 2145 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2146 repo := &automock.IntegrationSystemRepository{} 2147 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2148 return repo 2149 }, 2150 LabelSvcFn: UnusedLabelUpsertService, 2151 WebhookRepoFn: UnusedWebhookRepository, 2152 UIDServiceFn: UnusedUIDService, 2153 InputID: "foo", 2154 Input: updateInput, 2155 ExpectedErrMessage: testErr.Error(), 2156 }, 2157 { 2158 Name: "Returns error when application retrieval failed", 2159 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2160 AppRepoFn: func() *automock.ApplicationRepository { 2161 repo := &automock.ApplicationRepository{} 2162 repo.On("GetByID", ctx, tnt, id).Return(nil, testErr).Once() 2163 return repo 2164 }, 2165 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2166 repo := &automock.IntegrationSystemRepository{} 2167 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2168 return repo 2169 }, 2170 LabelSvcFn: UnusedLabelUpsertService, 2171 WebhookRepoFn: UnusedWebhookRepository, 2172 UIDServiceFn: UnusedUIDService, 2173 InputID: "foo", 2174 Input: updateInput, 2175 ExpectedErrMessage: testErr.Error(), 2176 }, 2177 { 2178 Name: "Returns error when Integration System does not exist", 2179 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2180 AppRepoFn: UnusedApplicationRepository, 2181 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2182 repo := &automock.IntegrationSystemRepository{} 2183 repo.On("Exists", ctx, intSysID).Return(false, nil).Once() 2184 return repo 2185 }, 2186 LabelSvcFn: UnusedLabelUpsertService, 2187 WebhookRepoFn: UnusedWebhookRepository, 2188 UIDServiceFn: UnusedUIDService, 2189 InputID: "foo", 2190 Input: updateInput, 2191 ExpectedErrMessage: errors.New("Object not found").Error(), 2192 }, 2193 { 2194 Name: "Returns error ensuring Integration System existence failed", 2195 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2196 AppRepoFn: UnusedApplicationRepository, 2197 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2198 repo := &automock.IntegrationSystemRepository{} 2199 repo.On("Exists", ctx, intSysID).Return(false, testErr).Once() 2200 return repo 2201 }, 2202 LabelSvcFn: UnusedLabelUpsertService, 2203 WebhookRepoFn: UnusedWebhookRepository, 2204 UIDServiceFn: UnusedUIDService, 2205 InputID: "foo", 2206 Input: updateInput, 2207 ExpectedErrMessage: testErr.Error(), 2208 }, 2209 { 2210 Name: "Returns error when setting label fails", 2211 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2212 AppRepoFn: func() *automock.ApplicationRepository { 2213 repo := &automock.ApplicationRepository{} 2214 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2215 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2216 repo.On("Exists", ctx, tnt, id).Return(true, nil).Once() 2217 return repo 2218 }, 2219 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2220 repo := &automock.IntegrationSystemRepository{} 2221 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2222 return repo 2223 }, 2224 LabelSvcFn: func() *automock.LabelService { 2225 svc := &automock.LabelService{} 2226 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(testErr).Once() 2227 return svc 2228 }, 2229 WebhookRepoFn: UnusedWebhookRepository, 2230 UIDServiceFn: UnusedUIDService, 2231 InputID: "foo", 2232 Input: updateInput, 2233 ExpectedErrMessage: testErr.Error(), 2234 }, 2235 { 2236 Name: "Returns error when app does not exist", 2237 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2238 AppRepoFn: func() *automock.ApplicationRepository { 2239 repo := &automock.ApplicationRepository{} 2240 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2241 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2242 repo.On("Exists", ctx, tnt, id).Return(false, nil).Once() 2243 return repo 2244 }, 2245 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2246 repo := &automock.IntegrationSystemRepository{} 2247 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2248 return repo 2249 }, 2250 LabelSvcFn: UnusedLabelUpsertService, 2251 WebhookRepoFn: UnusedWebhookRepository, 2252 UIDServiceFn: UnusedUIDService, 2253 InputID: "foo", 2254 Input: updateInput, 2255 ExpectedErrMessage: "Object not found", 2256 }, 2257 { 2258 Name: "Returns error when ensuring app existence fails", 2259 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2260 AppRepoFn: func() *automock.ApplicationRepository { 2261 repo := &automock.ApplicationRepository{} 2262 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2263 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2264 repo.On("Exists", ctx, tnt, id).Return(false, testErr).Once() 2265 return repo 2266 }, 2267 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2268 repo := &automock.IntegrationSystemRepository{} 2269 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2270 return repo 2271 }, 2272 LabelSvcFn: UnusedLabelUpsertService, 2273 WebhookRepoFn: UnusedWebhookRepository, 2274 UIDServiceFn: UnusedUIDService, 2275 InputID: "foo", 2276 Input: updateInput, 2277 ExpectedErrMessage: testErr.Error(), 2278 }, 2279 { 2280 Name: "Should return error when fetching applicationType label", 2281 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2282 AppRepoFn: func() *automock.ApplicationRepository { 2283 repo := &automock.ApplicationRepository{} 2284 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2285 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2286 repo.On("Exists", ctx, tnt, id).Return(true, nil).Twice() 2287 return repo 2288 }, 2289 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2290 repo := &automock.IntegrationSystemRepository{} 2291 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2292 return repo 2293 }, 2294 LabelSvcFn: func() *automock.LabelService { 2295 svc := &automock.LabelService{} 2296 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(nil).Once() 2297 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2298 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(nil, testErr).Once() 2299 return svc 2300 }, 2301 WebhookRepoFn: UnusedWebhookRepository, 2302 UIDServiceFn: UnusedUIDService, 2303 InputID: "foo", 2304 Input: updateInput, 2305 ExpectedErrMessage: testErr.Error(), 2306 }, 2307 { 2308 Name: "Should not create webhooks when applicationType label is missing", 2309 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2310 AppRepoFn: func() *automock.ApplicationRepository { 2311 repo := &automock.ApplicationRepository{} 2312 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2313 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2314 repo.On("Exists", ctx, tnt, id).Return(true, nil).Twice() 2315 return repo 2316 }, 2317 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2318 repo := &automock.IntegrationSystemRepository{} 2319 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2320 return repo 2321 }, 2322 LabelSvcFn: func() *automock.LabelService { 2323 svc := &automock.LabelService{} 2324 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(nil).Once() 2325 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2326 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(nil, apperrors.NewNotFoundErrorWithType(resource.Label)).Once() 2327 return svc 2328 }, 2329 WebhookRepoFn: UnusedWebhookRepository, 2330 UIDServiceFn: UnusedUIDService, 2331 InputID: "foo", 2332 Input: updateInput, 2333 ExpectedErrMessage: "", 2334 }, 2335 { 2336 Name: "Should return error when fetching applicationType label", 2337 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2338 AppRepoFn: func() *automock.ApplicationRepository { 2339 repo := &automock.ApplicationRepository{} 2340 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2341 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2342 repo.On("Exists", ctx, tnt, id).Return(true, nil).Twice() 2343 return repo 2344 }, 2345 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2346 repo := &automock.IntegrationSystemRepository{} 2347 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2348 return repo 2349 }, 2350 LabelSvcFn: func() *automock.LabelService { 2351 svc := &automock.LabelService{} 2352 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(nil).Once() 2353 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2354 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(appTypeLabel, nil).Once() 2355 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "ppmsProductVersionId").Return(nil, testErr).Once() 2356 return svc 2357 }, 2358 WebhookRepoFn: UnusedWebhookRepository, 2359 UIDServiceFn: UnusedUIDService, 2360 InputID: "foo", 2361 Input: updateInput, 2362 ExpectedErrMessage: testErr.Error(), 2363 }, 2364 { 2365 Name: "Should return error while creating webhook", 2366 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2367 AppRepoFn: func() *automock.ApplicationRepository { 2368 repo := &automock.ApplicationRepository{} 2369 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2370 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2371 repo.On("Exists", ctx, tnt, id).Return(true, nil).Twice() 2372 return repo 2373 }, 2374 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2375 repo := &automock.IntegrationSystemRepository{} 2376 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2377 return repo 2378 }, 2379 LabelSvcFn: func() *automock.LabelService { 2380 svc := &automock.LabelService{} 2381 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(nil).Once() 2382 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2383 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(appTypeLabel, nil).Once() 2384 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "ppmsProductVersionId").Return(ppmsVersionIDLabel, nil).Once() 2385 return svc 2386 }, 2387 WebhookRepoFn: func() *automock.WebhookRepository { 2388 webhookRepo := &automock.WebhookRepository{} 2389 webhookRepo.On("ListByReferenceObjectID", ctx, tnt, id, model.ApplicationWebhookReference).Return(nil, testErr) 2390 return webhookRepo 2391 }, 2392 ORDWebhookMapping: ordWebhookMapping, 2393 UIDServiceFn: UnusedUIDService, 2394 InputID: "foo", 2395 Input: updateInput, 2396 ExpectedErrMessage: testErr.Error(), 2397 }, 2398 { 2399 Name: "Not matching ord mapping configuration", 2400 AppNameNormalizer: &normalizer.DefaultNormalizator{}, 2401 AppRepoFn: func() *automock.ApplicationRepository { 2402 repo := &automock.ApplicationRepository{} 2403 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2404 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2405 repo.On("Exists", ctx, tnt, id).Return(true, nil).Twice() 2406 return repo 2407 }, 2408 IntSysRepoFn: func() *automock.IntegrationSystemRepository { 2409 repo := &automock.IntegrationSystemRepository{} 2410 repo.On("Exists", ctx, intSysID).Return(true, nil).Once() 2411 return repo 2412 }, 2413 LabelSvcFn: func() *automock.LabelService { 2414 svc := &automock.LabelService{} 2415 svc.On("UpsertLabel", ctx, tnt, intSysLabel).Return(nil).Once() 2416 svc.On("UpsertLabel", ctx, tnt, nameLabel).Return(nil).Once() 2417 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "applicationType").Return(appTypeLabel, nil).Once() 2418 svc.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, id, "ppmsProductVersionId").Return(ppmsVersionIDLabel, nil).Once() 2419 return svc 2420 }, 2421 WebhookRepoFn: UnusedWebhookRepository, 2422 ORDWebhookMapping: []application.ORDWebhookMapping{ 2423 { 2424 Type: "test-app-not-match", 2425 PpmsProductVersions: []string{"1"}, 2426 }, 2427 }, 2428 UIDServiceFn: UnusedUIDService, 2429 InputID: "foo", 2430 Input: updateInput, 2431 ExpectedErrMessage: "", 2432 }, 2433 } 2434 2435 for _, testCase := range testCases { 2436 t.Run(testCase.Name, func(t *testing.T) { 2437 resetModels() 2438 appNameNormalizer := testCase.AppNameNormalizer 2439 appRepo := testCase.AppRepoFn() 2440 intSysRepo := testCase.IntSysRepoFn() 2441 lblSvc := testCase.LabelSvcFn() 2442 webhookRepo := testCase.WebhookRepoFn() 2443 uidSvc := testCase.UIDServiceFn() 2444 svc := application.NewService(appNameNormalizer, nil, appRepo, webhookRepo, nil, nil, intSysRepo, lblSvc, nil, uidSvc, nil, "", testCase.ORDWebhookMapping) 2445 svc.SetTimestampGen(timestampGenFunc) 2446 2447 // WHEN 2448 err := svc.Update(ctx, testCase.InputID, testCase.Input) 2449 2450 // then 2451 if testCase.ExpectedErrMessage == "" { 2452 require.NoError(t, err) 2453 } else { 2454 require.Error(t, err) 2455 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 2456 } 2457 2458 mock.AssertExpectationsForObjects(t, uidSvc, webhookRepo, appRepo, intSysRepo, lblSvc) 2459 }) 2460 } 2461 } 2462 2463 func TestService_UpdateBaseURL(t *testing.T) { 2464 // GIVEN 2465 testErr := errors.New("Test error") 2466 ctxErr := errors.New("while loading tenant from context: cannot read tenant from context") 2467 2468 id := "foo" 2469 tnt := "tenant" 2470 externalTnt := "external-tnt" 2471 conditionTimestamp := time.Now() 2472 targetURL := "http://compass.kyma.local/api/event?myEvent=true" 2473 2474 var applicationModelBefore *model.Application 2475 var applicationModelAfter *model.Application 2476 2477 ctx := context.TODO() 2478 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 2479 2480 resetModels := func() { 2481 appName := "initial" 2482 description := "description" 2483 updatedBaseURL := "http://compass.kyma.local" 2484 url := "url.com" 2485 applicationModelBefore = fixModelApplicationWithAllUpdatableFields(id, appName, description, url, nil, nil, model.ApplicationStatusConditionConnected, conditionTimestamp) 2486 applicationModelAfter = fixModelApplicationWithAllUpdatableFields(id, appName, description, url, &updatedBaseURL, nil, model.ApplicationStatusConditionConnected, conditionTimestamp) 2487 } 2488 2489 resetModels() 2490 2491 testCases := []struct { 2492 Name string 2493 AppRepoFn func() *automock.ApplicationRepository 2494 Input model.ApplicationUpdateInput 2495 InputID string 2496 TargetURL string 2497 Context context.Context 2498 ExpectedErrMessage string 2499 }{ 2500 { 2501 Name: "Success", 2502 AppRepoFn: func() *automock.ApplicationRepository { 2503 repo := &automock.ApplicationRepository{} 2504 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2505 repo.On("Update", ctx, tnt, applicationModelAfter).Return(nil).Once() 2506 return repo 2507 }, 2508 InputID: id, 2509 TargetURL: targetURL, 2510 Context: ctx, 2511 ExpectedErrMessage: "", 2512 }, 2513 { 2514 Name: "Returns error when application update failed", 2515 AppRepoFn: func() *automock.ApplicationRepository { 2516 repo := &automock.ApplicationRepository{} 2517 repo.On("GetByID", ctx, tnt, id).Return(applicationModelBefore, nil).Once() 2518 repo.On("Update", ctx, tnt, applicationModelAfter).Return(testErr).Once() 2519 return repo 2520 }, 2521 InputID: id, 2522 TargetURL: targetURL, 2523 Context: ctx, 2524 ExpectedErrMessage: testErr.Error(), 2525 }, 2526 { 2527 Name: "Returns error when application retrieval failed", 2528 AppRepoFn: func() *automock.ApplicationRepository { 2529 repo := &automock.ApplicationRepository{} 2530 repo.On("GetByID", ctx, tnt, id).Return(nil, testErr).Once() 2531 repo.AssertNotCalled(t, "Update") 2532 return repo 2533 }, 2534 InputID: id, 2535 TargetURL: targetURL, 2536 Context: ctx, 2537 ExpectedErrMessage: testErr.Error(), 2538 }, 2539 { 2540 Name: "Returns error when tenant is not in the context", 2541 AppRepoFn: func() *automock.ApplicationRepository { 2542 repo := &automock.ApplicationRepository{} 2543 repo.AssertNotCalled(t, "Update") 2544 repo.AssertNotCalled(t, "GetByID") 2545 2546 return repo 2547 }, 2548 InputID: id, 2549 TargetURL: targetURL, 2550 Context: context.Background(), 2551 ExpectedErrMessage: ctxErr.Error(), 2552 }, 2553 { 2554 Name: "Does not update Application when BaseURL is already set", 2555 AppRepoFn: func() *automock.ApplicationRepository { 2556 repo := &automock.ApplicationRepository{} 2557 repo.AssertNotCalled(t, "Update") 2558 repo.On("GetByID", ctx, tnt, id).Return(applicationModelAfter, nil).Once() 2559 2560 return repo 2561 }, 2562 InputID: id, 2563 TargetURL: targetURL, 2564 Context: ctx, 2565 ExpectedErrMessage: "", 2566 }, 2567 } 2568 2569 for _, testCase := range testCases { 2570 t.Run(testCase.Name, func(t *testing.T) { 2571 resetModels() 2572 appRepo := testCase.AppRepoFn() 2573 svc := application.NewService(nil, nil, appRepo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 2574 2575 // WHEN 2576 err := svc.UpdateBaseURL(testCase.Context, testCase.InputID, testCase.TargetURL) 2577 2578 // then 2579 if testCase.ExpectedErrMessage == "" { 2580 require.NoError(t, err) 2581 } else { 2582 require.Error(t, err) 2583 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 2584 } 2585 2586 appRepo.AssertExpectations(t) 2587 }) 2588 } 2589 } 2590 2591 func TestService_Delete(t *testing.T) { 2592 // GIVEN 2593 testErr := errors.New("Test error") 2594 id := "foo" 2595 desc := "Lorem ipsum" 2596 tnt := "tenant" 2597 externalTnt := "external-tnt" 2598 2599 scenarios := []interface{}{"Easter"} 2600 scenarioLabel := &model.Label{ 2601 ID: uuid.New().String(), 2602 Key: model.ScenariosKey, 2603 Value: scenarios, 2604 } 2605 2606 emptyScenarioLabel := &model.Label{ 2607 ID: uuid.New().String(), 2608 Key: model.ScenariosKey, 2609 Value: []interface{}{}, 2610 } 2611 2612 applicationModel := &model.Application{ 2613 Name: "foo", 2614 Description: &desc, 2615 BaseEntity: &model.BaseEntity{ID: id}, 2616 } 2617 2618 ctx := context.TODO() 2619 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 2620 2621 testCases := []struct { 2622 Name string 2623 AppRepoFn func() *automock.ApplicationRepository 2624 LabelRepoFn func() *automock.LabelRepository 2625 Input model.ApplicationRegisterInput 2626 InputID string 2627 ExpectedErrMessage string 2628 }{ 2629 { 2630 Name: "Success", 2631 AppRepoFn: func() *automock.ApplicationRepository { 2632 repo := &automock.ApplicationRepository{} 2633 repo.On("Delete", ctx, tnt, applicationModel.ID).Return(nil).Once() 2634 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2635 return repo 2636 }, 2637 LabelRepoFn: func() *automock.LabelRepository { 2638 repo := &automock.LabelRepository{} 2639 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(emptyScenarioLabel, nil).Once() 2640 return repo 2641 }, 2642 InputID: id, 2643 ExpectedErrMessage: "", 2644 }, 2645 { 2646 Name: "Return error when application is part of a scenario", 2647 AppRepoFn: func() *automock.ApplicationRepository { 2648 repo := &automock.ApplicationRepository{} 2649 repo.AssertNotCalled(t, "Delete") 2650 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2651 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(applicationModel, nil).Once() 2652 return repo 2653 }, 2654 LabelRepoFn: func() *automock.LabelRepository { 2655 repo := &automock.LabelRepository{} 2656 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(scenarioLabel, nil).Once() 2657 return repo 2658 }, 2659 InputID: id, 2660 ExpectedErrMessage: "System foo is part of the following formations : Easter", 2661 }, 2662 { 2663 Name: "Return error when fails to get application by ID", 2664 AppRepoFn: func() *automock.ApplicationRepository { 2665 repo := &automock.ApplicationRepository{} 2666 repo.AssertNotCalled(t, "Delete") 2667 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2668 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(nil, testErr).Once() 2669 return repo 2670 }, 2671 LabelRepoFn: func() *automock.LabelRepository { 2672 repo := &automock.LabelRepository{} 2673 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(scenarioLabel, nil).Once() 2674 return repo 2675 }, 2676 InputID: id, 2677 ExpectedErrMessage: testErr.Error(), 2678 }, 2679 { 2680 Name: "Returns error when application deletion failed", 2681 AppRepoFn: func() *automock.ApplicationRepository { 2682 repo := &automock.ApplicationRepository{} 2683 repo.On("Delete", ctx, tnt, applicationModel.ID).Return(testErr).Once() 2684 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2685 return repo 2686 }, 2687 LabelRepoFn: func() *automock.LabelRepository { 2688 repo := &automock.LabelRepository{} 2689 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(emptyScenarioLabel, nil).Once() 2690 return repo 2691 }, 2692 InputID: id, 2693 ExpectedErrMessage: testErr.Error(), 2694 }, 2695 } 2696 2697 for _, testCase := range testCases { 2698 t.Run(testCase.Name, func(t *testing.T) { 2699 appRepo := testCase.AppRepoFn() 2700 labelRepo := testCase.LabelRepoFn() 2701 svc := application.NewService(nil, nil, appRepo, nil, nil, labelRepo, nil, nil, nil, nil, nil, "", nil) 2702 2703 // WHEN 2704 err := svc.Delete(ctx, testCase.InputID) 2705 2706 // then 2707 if testCase.ExpectedErrMessage == "" { 2708 require.NoError(t, err) 2709 } else { 2710 require.Error(t, err) 2711 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 2712 } 2713 2714 mock.AssertExpectationsForObjects(t, appRepo, labelRepo) 2715 }) 2716 } 2717 } 2718 2719 func TestService_Unpair(t *testing.T) { 2720 // GIVEN 2721 testErr := errors.New("Test error") 2722 formationAndRuntimeError := errors.New("The operation is not allowed [reason=System foo is still used and cannot be deleted. Unassign the system from the following formations first: Easter. Then, unassign the system from the following runtimes, too: test-runtime]") 2723 id := "foo" 2724 desc := "Lorem ipsum" 2725 tnt := "tenant" 2726 externalTnt := "external-tnt" 2727 2728 scenarios := []interface{}{"Easter"} 2729 scenarioLabel := &model.Label{ 2730 ID: uuid.New().String(), 2731 Key: model.ScenariosKey, 2732 Value: scenarios, 2733 } 2734 2735 emptyScenarioLabel := &model.Label{ 2736 ID: uuid.New().String(), 2737 Key: model.ScenariosKey, 2738 Value: []interface{}{}, 2739 } 2740 2741 timestamp := time.Now() 2742 2743 applicationModel := &model.Application{ 2744 Name: "foo", 2745 Description: &desc, 2746 Status: &model.ApplicationStatus{ 2747 Condition: model.ApplicationStatusConditionConnected, 2748 Timestamp: timestamp, 2749 }, 2750 BaseEntity: &model.BaseEntity{ID: id}, 2751 } 2752 2753 applicationModelWithInitialStatus := &model.Application{ 2754 Name: "foo", 2755 Description: &desc, 2756 Status: &model.ApplicationStatus{ 2757 Condition: model.ApplicationStatusConditionInitial, 2758 Timestamp: timestamp, 2759 }, 2760 BaseEntity: &model.BaseEntity{ID: id}, 2761 } 2762 2763 runtimeModel := &model.Runtime{ 2764 Name: "test-runtime", 2765 } 2766 2767 ctx := context.Background() 2768 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 2769 2770 testCases := []struct { 2771 Name string 2772 AppRepoFn func() *automock.ApplicationRepository 2773 LabelRepoFn func() *automock.LabelRepository 2774 RuntimeRepoFn func() *automock.RuntimeRepository 2775 Input model.ApplicationRegisterInput 2776 ContextFn func() context.Context 2777 InputID string 2778 ExpectedErrMessage string 2779 }{ 2780 { 2781 Name: "Success", 2782 AppRepoFn: func() *automock.ApplicationRepository { 2783 repo := &automock.ApplicationRepository{} 2784 repo.On("Update", ctx, tnt, applicationModelWithInitialStatus).Return(nil).Once() 2785 repo.On("Exists", ctx, tnt, applicationModelWithInitialStatus.ID).Return(true, nil).Once() 2786 repo.On("GetByID", ctx, tnt, applicationModelWithInitialStatus.ID).Return(applicationModelWithInitialStatus, nil).Once() 2787 return repo 2788 }, 2789 LabelRepoFn: func() *automock.LabelRepository { 2790 repo := &automock.LabelRepository{} 2791 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(emptyScenarioLabel, nil) 2792 return repo 2793 }, 2794 RuntimeRepoFn: func() *automock.RuntimeRepository { 2795 repo := &automock.RuntimeRepository{} 2796 repo.AssertNotCalled(t, "ListAll") 2797 return repo 2798 }, 2799 ContextFn: func() context.Context { 2800 ctx := context.Background() 2801 2802 return ctx 2803 }, 2804 InputID: id, 2805 }, 2806 { 2807 Name: "Success when application is part of a scenario but not with runtime", 2808 AppRepoFn: func() *automock.ApplicationRepository { 2809 repo := &automock.ApplicationRepository{} 2810 repo.On("Update", ctx, tnt, applicationModel).Return(nil).Once() 2811 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2812 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(applicationModel, nil).Once() 2813 return repo 2814 }, 2815 LabelRepoFn: func() *automock.LabelRepository { 2816 repo := &automock.LabelRepository{} 2817 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(scenarioLabel, nil) 2818 return repo 2819 }, 2820 RuntimeRepoFn: func() *automock.RuntimeRepository { 2821 repo := &automock.RuntimeRepository{} 2822 repo.On("ListAll", ctx, tnt, mock.Anything).Return(scenarioLabel).Return([]*model.Runtime{}, nil) 2823 return repo 2824 }, 2825 ContextFn: func() context.Context { 2826 ctx := context.Background() 2827 2828 return ctx 2829 }, 2830 InputID: id, 2831 }, 2832 { 2833 Name: "Success when operation type is SYNC and sets the application status to INITIAL", 2834 AppRepoFn: func() *automock.ApplicationRepository { 2835 repo := &automock.ApplicationRepository{} 2836 repo.On("Update", mock.Anything, tnt, applicationModelWithInitialStatus).Return(nil).Once() 2837 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2838 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(applicationModel, nil).Once() 2839 return repo 2840 }, 2841 LabelRepoFn: func() *automock.LabelRepository { 2842 repo := &automock.LabelRepository{} 2843 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(scenarioLabel, nil) 2844 return repo 2845 }, 2846 RuntimeRepoFn: func() *automock.RuntimeRepository { 2847 repo := &automock.RuntimeRepository{} 2848 repo.On("ListAll", ctx, tnt, mock.Anything).Return(scenarioLabel).Return([]*model.Runtime{}, nil) 2849 return repo 2850 }, 2851 InputID: id, 2852 ContextFn: func() context.Context { 2853 backgroundCtx := context.Background() 2854 return backgroundCtx 2855 }, 2856 }, 2857 { 2858 Name: "Success when operation type is ASYNC and does not change the application status", 2859 AppRepoFn: func() *automock.ApplicationRepository { 2860 repo := &automock.ApplicationRepository{} 2861 repo.On("Update", mock.Anything, tnt, applicationModel).Return(nil).Once() 2862 repo.On("Exists", mock.Anything, tnt, applicationModel.ID).Return(true, nil).Once() 2863 repo.On("GetByID", mock.Anything, tnt, applicationModel.ID).Return(applicationModel, nil).Once() 2864 return repo 2865 }, 2866 LabelRepoFn: func() *automock.LabelRepository { 2867 repo := &automock.LabelRepository{} 2868 repo.On("GetByKey", mock.Anything, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(scenarioLabel, nil) 2869 return repo 2870 }, 2871 RuntimeRepoFn: func() *automock.RuntimeRepository { 2872 repo := &automock.RuntimeRepository{} 2873 repo.On("ListAll", mock.Anything, tnt, mock.Anything).Return(scenarioLabel).Return([]*model.Runtime{}, nil) 2874 return repo 2875 }, 2876 InputID: id, 2877 ContextFn: func() context.Context { 2878 backgroundCtx := context.Background() 2879 backgroundCtx = operation.SaveModeToContext(backgroundCtx, graphql.OperationModeAsync) 2880 return backgroundCtx 2881 }, 2882 }, 2883 { 2884 Name: "Returns error when application fetch failed", 2885 AppRepoFn: func() *automock.ApplicationRepository { 2886 repo := &automock.ApplicationRepository{} 2887 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(nil, testErr).Once() 2888 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2889 repo.AssertNotCalled(t, "Update") 2890 return repo 2891 }, 2892 LabelRepoFn: func() *automock.LabelRepository { 2893 repo := &automock.LabelRepository{} 2894 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(emptyScenarioLabel, nil) 2895 return repo 2896 }, 2897 RuntimeRepoFn: func() *automock.RuntimeRepository { 2898 repo := &automock.RuntimeRepository{} 2899 repo.AssertNotCalled(t, "ListAll") 2900 return repo 2901 }, 2902 ContextFn: func() context.Context { 2903 ctx := context.Background() 2904 2905 return ctx 2906 }, 2907 InputID: id, 2908 ExpectedErrMessage: testErr.Error(), 2909 }, 2910 { 2911 Name: "Returns error when application is part of a scenario with runtime", 2912 AppRepoFn: func() *automock.ApplicationRepository { 2913 repo := &automock.ApplicationRepository{} 2914 repo.AssertNotCalled(t, "Delete") 2915 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2916 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(applicationModel, nil).Once() 2917 repo.AssertNotCalled(t, "Update") 2918 return repo 2919 }, 2920 LabelRepoFn: func() *automock.LabelRepository { 2921 repo := &automock.LabelRepository{} 2922 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(scenarioLabel, nil) 2923 return repo 2924 }, 2925 RuntimeRepoFn: func() *automock.RuntimeRepository { 2926 repo := &automock.RuntimeRepository{} 2927 repo.On("ListAll", ctx, tnt, mock.Anything).Return(scenarioLabel).Return([]*model.Runtime{runtimeModel}, nil) 2928 return repo 2929 }, 2930 ContextFn: func() context.Context { 2931 ctx := context.Background() 2932 2933 return ctx 2934 }, 2935 InputID: id, 2936 ExpectedErrMessage: formationAndRuntimeError.Error(), 2937 }, 2938 { 2939 Name: "Returns error when update fails", 2940 AppRepoFn: func() *automock.ApplicationRepository { 2941 repo := &automock.ApplicationRepository{} 2942 repo.AssertNotCalled(t, "Delete") 2943 repo.On("Update", ctx, tnt, applicationModel).Return(testErr).Once() 2944 repo.On("Exists", ctx, tnt, applicationModel.ID).Return(true, nil).Once() 2945 repo.On("GetByID", ctx, tnt, applicationModel.ID).Return(applicationModel, nil).Once() 2946 return repo 2947 }, 2948 LabelRepoFn: func() *automock.LabelRepository { 2949 repo := &automock.LabelRepository{} 2950 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationModel.ID, model.ScenariosKey).Return(emptyScenarioLabel, nil) 2951 return repo 2952 }, 2953 RuntimeRepoFn: func() *automock.RuntimeRepository { 2954 repo := &automock.RuntimeRepository{} 2955 repo.AssertNotCalled(t, "ListAll") 2956 return repo 2957 }, 2958 ContextFn: func() context.Context { 2959 ctx := context.Background() 2960 2961 return ctx 2962 }, 2963 InputID: id, 2964 ExpectedErrMessage: testErr.Error(), 2965 }, 2966 } 2967 2968 for _, testCase := range testCases { 2969 t.Run(testCase.Name, func(t *testing.T) { 2970 appRepo := testCase.AppRepoFn() 2971 labelRepo := testCase.LabelRepoFn() 2972 runtimeRepo := testCase.RuntimeRepoFn() 2973 ctx := testCase.ContextFn() 2974 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 2975 svc := application.NewService(nil, nil, appRepo, nil, runtimeRepo, labelRepo, nil, nil, nil, nil, nil, "", nil) 2976 svc.SetTimestampGen(func() time.Time { return timestamp }) 2977 // WHEN 2978 err := svc.Unpair(ctx, testCase.InputID) 2979 2980 // then 2981 if testCase.ExpectedErrMessage == "" { 2982 require.NoError(t, err) 2983 } else { 2984 require.Error(t, err) 2985 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 2986 } 2987 2988 mock.AssertExpectationsForObjects(t, appRepo, labelRepo, runtimeRepo) 2989 }) 2990 } 2991 } 2992 2993 func TestService_Merge(t *testing.T) { 2994 // GIVEN 2995 testErr := errors.New("Test error") 2996 destID := "foo" 2997 srcID := "bar" 2998 tnt := "tenant" 2999 externalTnt := "external-tnt" 3000 baseURL := "http://localhost.com" 3001 templateID := "12346789" 3002 otherTemplateID := "qwerty" 3003 destName := "dest app" 3004 srcName := "src app" 3005 srcDescription := "Long src description" 3006 selfRegDistLabelKey := "subscriptionProviderId" 3007 3008 labelKey1 := model.ScenariosKey 3009 labelKey2 := "managed" 3010 var labelValue1 []interface{} 3011 labelValue2 := []interface{}{"Easter", "Bunny"} 3012 3013 upsertLabelValues := make(map[string]interface{}) 3014 upsertLabelValues[labelKey1] = []string{"Easter", "Bunny"} 3015 upsertLabelValues[labelKey2] = "true" 3016 3017 upsertLabelValuesWithManagedFalse := make(map[string]interface{}) 3018 upsertLabelValuesWithManagedFalse[labelKey1] = []string{"Easter", "Bunny"} 3019 upsertLabelValuesWithManagedFalse[labelKey2] = "false" 3020 3021 srcAppLabels := fixApplicationLabels(srcID, labelKey1, labelKey2, labelValue1, "true") 3022 destAppLabels := fixApplicationLabels(srcID, labelKey1, labelKey2, labelValue2, "false") 3023 srcAppLabelsWithFalseManaged := fixApplicationLabels(srcID, labelKey1, labelKey2, labelValue1, "false") 3024 appTemplateLabelsWithSelfRegDistLabelKey := map[string]*model.Label{ 3025 selfRegDistLabelKey: { 3026 ID: "abc", 3027 Tenant: str.Ptr(tnt), 3028 Key: selfRegDistLabelKey, 3029 Value: labelValue1, 3030 ObjectID: templateID, 3031 ObjectType: model.AppTemplateLabelableObject, 3032 }, 3033 } 3034 3035 srcModel := fixDetailedModelApplication(t, srcID, tnt, srcName, srcDescription) 3036 srcModel.ApplicationTemplateID = &templateID 3037 srcModel.Status.Timestamp = time.Time{} 3038 3039 destModel := fixModelApplication(destID, tnt, destName, "") 3040 destModel.ApplicationTemplateID = &templateID 3041 destModel.BaseURL = srcModel.BaseURL 3042 destModel.Status.Timestamp = time.Time{} 3043 3044 mergedDestModel := fixDetailedModelApplication(t, destID, tnt, destName, srcDescription) 3045 mergedDestModel.ApplicationTemplateID = &templateID 3046 mergedDestModel.Status.Timestamp = time.Time{} 3047 3048 srcModelWithoutBaseURL := fixDetailedModelApplication(t, srcID, tnt, srcName, srcDescription) 3049 srcModelWithoutBaseURL.BaseURL = nil 3050 3051 srcModelWithDifferentBaseURL := fixDetailedModelApplication(t, srcID, tnt, srcName, srcDescription) 3052 srcModelWithDifferentBaseURL.BaseURL = &baseURL 3053 3054 srcModelWithDifferentTemplateID := fixDetailedModelApplication(t, srcID, tnt, srcName, srcDescription) 3055 srcModelWithDifferentTemplateID.ApplicationTemplateID = &otherTemplateID 3056 3057 srcModelConnected := fixDetailedModelApplication(t, srcID, tnt, srcName, srcDescription) 3058 srcModelConnected.Status.Condition = model.ApplicationStatusConditionConnected 3059 srcModelConnected.ApplicationTemplateID = &templateID 3060 3061 ctx := context.TODO() 3062 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 3063 3064 testCases := []struct { 3065 Name string 3066 AppRepoFn func() *automock.ApplicationRepository 3067 LabelRepoFn func() *automock.LabelRepository 3068 LabelUpsertSvcFn func() *automock.LabelService 3069 ExpectedDestinationApplication *model.Application 3070 Ctx context.Context 3071 SourceID string 3072 DestinationID string 3073 ExpectedErrMessage string 3074 }{ 3075 { 3076 Name: "Success", 3077 AppRepoFn: func() *automock.ApplicationRepository { 3078 repo := &automock.ApplicationRepository{} 3079 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3080 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3081 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3082 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Twice() 3083 repo.On("Update", ctx, tnt, destModel).Return(nil).Once() 3084 repo.On("Delete", ctx, tnt, srcModel.ID).Return(nil).Once() 3085 return repo 3086 }, 3087 LabelRepoFn: func() *automock.LabelRepository { 3088 repo := &automock.LabelRepository{} 3089 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3090 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3091 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3092 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(map[string]*model.Label{}, nil) 3093 return repo 3094 }, 3095 LabelUpsertSvcFn: func() *automock.LabelService { 3096 svc := &automock.LabelService{} 3097 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, destModel.ID, upsertLabelValues).Return(nil) 3098 return svc 3099 }, 3100 Ctx: ctx, 3101 DestinationID: destID, 3102 SourceID: srcID, 3103 ExpectedDestinationApplication: mergedDestModel, 3104 ExpectedErrMessage: "", 3105 }, 3106 { 3107 Name: "Success with managed \"false\" label when both labels are \"false\"", 3108 AppRepoFn: func() *automock.ApplicationRepository { 3109 repo := &automock.ApplicationRepository{} 3110 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3111 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3112 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3113 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Twice() 3114 repo.On("Update", ctx, tnt, destModel).Return(nil).Once() 3115 repo.On("Delete", ctx, tnt, srcModel.ID).Return(nil).Once() 3116 return repo 3117 }, 3118 LabelRepoFn: func() *automock.LabelRepository { 3119 repo := &automock.LabelRepository{} 3120 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3121 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabelsWithFalseManaged, nil) 3122 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3123 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(map[string]*model.Label{}, nil) 3124 return repo 3125 }, 3126 LabelUpsertSvcFn: func() *automock.LabelService { 3127 svc := &automock.LabelService{} 3128 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, destModel.ID, upsertLabelValuesWithManagedFalse).Return(nil) 3129 return svc 3130 }, 3131 Ctx: ctx, 3132 DestinationID: destID, 3133 SourceID: srcID, 3134 ExpectedDestinationApplication: mergedDestModel, 3135 ExpectedErrMessage: "", 3136 }, 3137 { 3138 Name: "Error when tenant is not in context", 3139 AppRepoFn: func() *automock.ApplicationRepository { 3140 repo := &automock.ApplicationRepository{} 3141 repo.AssertNotCalled(t, "GetByID") 3142 repo.AssertNotCalled(t, "Exists") 3143 repo.AssertNotCalled(t, "Update") 3144 repo.AssertNotCalled(t, "Delete") 3145 return repo 3146 }, 3147 LabelRepoFn: func() *automock.LabelRepository { 3148 repo := &automock.LabelRepository{} 3149 repo.AssertNotCalled(t, "GetByKey") 3150 repo.AssertNotCalled(t, "ListForObject") 3151 return repo 3152 }, 3153 LabelUpsertSvcFn: func() *automock.LabelService { 3154 svc := &automock.LabelService{} 3155 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3156 return svc 3157 }, 3158 Ctx: context.Background(), 3159 DestinationID: destID, 3160 SourceID: srcID, 3161 ExpectedErrMessage: "while loading tenant from context: cannot read tenant from context", 3162 }, 3163 { 3164 Name: "Error when cannot get destination application", 3165 AppRepoFn: func() *automock.ApplicationRepository { 3166 repo := &automock.ApplicationRepository{} 3167 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3168 repo.On("GetByID", ctx, tnt, destModel.ID).Return(nil, testErr).Once() 3169 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3170 repo.AssertNotCalled(t, "Update") 3171 repo.AssertNotCalled(t, "Delete") 3172 return repo 3173 }, 3174 LabelRepoFn: func() *automock.LabelRepository { 3175 repo := &automock.LabelRepository{} 3176 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3177 repo.AssertNotCalled(t, "ListForObject") 3178 return repo 3179 }, 3180 LabelUpsertSvcFn: func() *automock.LabelService { 3181 svc := &automock.LabelService{} 3182 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3183 return svc 3184 }, 3185 Ctx: ctx, 3186 DestinationID: destID, 3187 SourceID: srcID, 3188 ExpectedErrMessage: testErr.Error(), 3189 }, 3190 { 3191 Name: "Error when cannot get source application", 3192 AppRepoFn: func() *automock.ApplicationRepository { 3193 repo := &automock.ApplicationRepository{} 3194 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(nil, testErr).Once() 3195 repo.AssertNotCalled(t, "Exists") 3196 repo.AssertNotCalled(t, "Update") 3197 repo.AssertNotCalled(t, "Delete") 3198 return repo 3199 }, 3200 LabelRepoFn: func() *automock.LabelRepository { 3201 repo := &automock.LabelRepository{} 3202 repo.AssertNotCalled(t, "GetByKey") 3203 repo.AssertNotCalled(t, "ListForObject") 3204 return repo 3205 }, 3206 LabelUpsertSvcFn: func() *automock.LabelService { 3207 svc := &automock.LabelService{} 3208 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3209 return svc 3210 }, 3211 Ctx: ctx, 3212 DestinationID: destID, 3213 SourceID: srcID, 3214 ExpectedErrMessage: testErr.Error(), 3215 }, 3216 { 3217 Name: "Error when source app and destination app templates do not match", 3218 AppRepoFn: func() *automock.ApplicationRepository { 3219 repo := &automock.ApplicationRepository{} 3220 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3221 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModelWithDifferentTemplateID, nil).Once() 3222 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3223 repo.AssertNotCalled(t, "Update") 3224 repo.AssertNotCalled(t, "Delete") 3225 return repo 3226 }, 3227 LabelRepoFn: func() *automock.LabelRepository { 3228 repo := &automock.LabelRepository{} 3229 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3230 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3231 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3232 repo.AssertNotCalled(t, "ListForObject") 3233 return repo 3234 }, 3235 LabelUpsertSvcFn: func() *automock.LabelService { 3236 svc := &automock.LabelService{} 3237 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3238 return svc 3239 }, 3240 Ctx: ctx, 3241 DestinationID: destID, 3242 SourceID: srcID, 3243 ExpectedErrMessage: "Application templates are not the same. Destination app template: 12346789. Source app template: qwerty", 3244 }, 3245 { 3246 Name: "Error when source app and destination app base url do not match", 3247 AppRepoFn: func() *automock.ApplicationRepository { 3248 repo := &automock.ApplicationRepository{} 3249 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3250 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModelWithDifferentBaseURL, nil).Once() 3251 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3252 repo.AssertNotCalled(t, "Update") 3253 repo.AssertNotCalled(t, "Delete") 3254 return repo 3255 }, 3256 LabelRepoFn: func() *automock.LabelRepository { 3257 repo := &automock.LabelRepository{} 3258 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3259 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3260 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3261 repo.AssertNotCalled(t, "ListForObject") 3262 return repo 3263 }, 3264 LabelUpsertSvcFn: func() *automock.LabelService { 3265 svc := &automock.LabelService{} 3266 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3267 return svc 3268 }, 3269 Ctx: ctx, 3270 DestinationID: destID, 3271 SourceID: srcID, 3272 ExpectedErrMessage: "BaseURL for applications foo and bar are not the same.", 3273 }, 3274 { 3275 Name: "Error when source app is in CONNECTED status", 3276 AppRepoFn: func() *automock.ApplicationRepository { 3277 repo := &automock.ApplicationRepository{} 3278 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3279 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModelConnected, nil).Once() 3280 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3281 repo.AssertNotCalled(t, "Update") 3282 repo.AssertNotCalled(t, "Delete") 3283 return repo 3284 }, 3285 LabelRepoFn: func() *automock.LabelRepository { 3286 repo := &automock.LabelRepository{} 3287 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3288 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3289 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3290 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(map[string]*model.Label{}, nil) 3291 return repo 3292 }, 3293 LabelUpsertSvcFn: func() *automock.LabelService { 3294 svc := &automock.LabelService{} 3295 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3296 return svc 3297 }, 3298 Ctx: ctx, 3299 DestinationID: destID, 3300 SourceID: srcID, 3301 ExpectedErrMessage: "Cannot merge application with id bar, because it is in a CONNECTED status", 3302 }, 3303 { 3304 Name: "Error when source deletion fails", 3305 AppRepoFn: func() *automock.ApplicationRepository { 3306 repo := &automock.ApplicationRepository{} 3307 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3308 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3309 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Twice() 3310 repo.AssertNotCalled(t, "Update") 3311 repo.On("Delete", ctx, tnt, srcModel.ID).Return(testErr).Once() 3312 return repo 3313 }, 3314 LabelRepoFn: func() *automock.LabelRepository { 3315 repo := &automock.LabelRepository{} 3316 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3317 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3318 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3319 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(map[string]*model.Label{}, nil) 3320 return repo 3321 }, 3322 LabelUpsertSvcFn: func() *automock.LabelService { 3323 svc := &automock.LabelService{} 3324 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3325 return svc 3326 }, 3327 Ctx: ctx, 3328 DestinationID: destID, 3329 SourceID: srcID, 3330 ExpectedErrMessage: testErr.Error(), 3331 }, 3332 { 3333 Name: "Error when destination app update fails", 3334 AppRepoFn: func() *automock.ApplicationRepository { 3335 repo := &automock.ApplicationRepository{} 3336 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3337 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3338 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Twice() 3339 repo.On("Update", ctx, tnt, mergedDestModel).Return(testErr) 3340 repo.On("Delete", ctx, tnt, srcModel.ID).Return(nil).Once() 3341 return repo 3342 }, 3343 LabelRepoFn: func() *automock.LabelRepository { 3344 repo := &automock.LabelRepository{} 3345 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3346 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3347 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3348 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(map[string]*model.Label{}, nil) 3349 return repo 3350 }, 3351 LabelUpsertSvcFn: func() *automock.LabelService { 3352 svc := &automock.LabelService{} 3353 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3354 return svc 3355 }, 3356 Ctx: ctx, 3357 DestinationID: destID, 3358 SourceID: srcID, 3359 ExpectedErrMessage: testErr.Error(), 3360 }, 3361 { 3362 Name: "Error when update labels fails", 3363 AppRepoFn: func() *automock.ApplicationRepository { 3364 repo := &automock.ApplicationRepository{} 3365 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3366 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3367 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Twice() 3368 repo.On("Update", ctx, tnt, mergedDestModel).Return(nil) 3369 repo.On("Delete", ctx, tnt, srcModel.ID).Return(nil).Once() 3370 return repo 3371 }, 3372 LabelRepoFn: func() *automock.LabelRepository { 3373 repo := &automock.LabelRepository{} 3374 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3375 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3376 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3377 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(map[string]*model.Label{}, nil) 3378 return repo 3379 }, 3380 LabelUpsertSvcFn: func() *automock.LabelService { 3381 svc := &automock.LabelService{} 3382 svc.On("UpsertMultipleLabels", ctx, tnt, model.ApplicationLabelableObject, destModel.ID, upsertLabelValues).Return(testErr) 3383 return svc 3384 }, 3385 Ctx: ctx, 3386 DestinationID: destID, 3387 SourceID: srcID, 3388 ExpectedErrMessage: testErr.Error(), 3389 }, 3390 { 3391 Name: "Error when app template has label subscriptionProviderId", 3392 AppRepoFn: func() *automock.ApplicationRepository { 3393 repo := &automock.ApplicationRepository{} 3394 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3395 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3396 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3397 repo.AssertNotCalled(t, "Update") 3398 repo.AssertNotCalled(t, "Delete") 3399 return repo 3400 }, 3401 LabelRepoFn: func() *automock.LabelRepository { 3402 repo := &automock.LabelRepository{} 3403 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3404 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3405 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3406 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(appTemplateLabelsWithSelfRegDistLabelKey, nil) 3407 3408 return repo 3409 }, 3410 LabelUpsertSvcFn: func() *automock.LabelService { 3411 svc := &automock.LabelService{} 3412 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3413 return svc 3414 }, 3415 Ctx: ctx, 3416 DestinationID: destID, 3417 SourceID: srcID, 3418 ExpectedErrMessage: "app template: 12346789 has label subscriptionProviderId", 3419 }, 3420 { 3421 Name: "Error when cannot get application template labels", 3422 AppRepoFn: func() *automock.ApplicationRepository { 3423 repo := &automock.ApplicationRepository{} 3424 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3425 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3426 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3427 repo.AssertNotCalled(t, "Update") 3428 repo.AssertNotCalled(t, "Delete") 3429 return repo 3430 }, 3431 LabelRepoFn: func() *automock.LabelRepository { 3432 repo := &automock.LabelRepository{} 3433 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3434 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(srcAppLabels, nil) 3435 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3436 repo.On("ListForObject", ctx, tnt, model.AppTemplateLabelableObject, *srcModel.ApplicationTemplateID).Return(nil, testErr) 3437 3438 return repo 3439 }, 3440 LabelUpsertSvcFn: func() *automock.LabelService { 3441 svc := &automock.LabelService{} 3442 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3443 return svc 3444 }, 3445 Ctx: ctx, 3446 DestinationID: destID, 3447 SourceID: srcID, 3448 ExpectedErrMessage: testErr.Error(), 3449 }, 3450 { 3451 Name: "Error while checking if source app exists", 3452 AppRepoFn: func() *automock.ApplicationRepository { 3453 repo := &automock.ApplicationRepository{} 3454 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3455 repo.On("Exists", ctx, tnt, srcModel.ID).Return(false, testErr).Once() 3456 repo.AssertNotCalled(t, "Update") 3457 repo.AssertNotCalled(t, "Delete") 3458 return repo 3459 }, 3460 LabelRepoFn: UnusedLabelRepository, 3461 LabelUpsertSvcFn: func() *automock.LabelService { 3462 svc := &automock.LabelService{} 3463 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3464 return svc 3465 }, 3466 Ctx: ctx, 3467 DestinationID: destID, 3468 SourceID: srcID, 3469 ExpectedErrMessage: testErr.Error(), 3470 }, 3471 { 3472 Name: "Error while listing source app labels", 3473 AppRepoFn: func() *automock.ApplicationRepository { 3474 repo := &automock.ApplicationRepository{} 3475 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3476 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3477 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3478 repo.AssertNotCalled(t, "Update") 3479 repo.AssertNotCalled(t, "Delete") 3480 return repo 3481 }, 3482 LabelRepoFn: func() *automock.LabelRepository { 3483 repo := &automock.LabelRepository{} 3484 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3485 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID).Return(nil, testErr) 3486 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(destAppLabels, nil) 3487 return repo 3488 }, 3489 LabelUpsertSvcFn: func() *automock.LabelService { 3490 svc := &automock.LabelService{} 3491 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3492 return svc 3493 }, 3494 Ctx: ctx, 3495 DestinationID: destID, 3496 SourceID: srcID, 3497 ExpectedErrMessage: testErr.Error(), 3498 }, 3499 { 3500 Name: "Error while listing destination app labels", 3501 AppRepoFn: func() *automock.ApplicationRepository { 3502 repo := &automock.ApplicationRepository{} 3503 repo.On("GetByID", ctx, tnt, destModel.ID).Return(destModel, nil).Once() 3504 repo.On("GetByID", ctx, tnt, srcModel.ID).Return(srcModel, nil).Once() 3505 repo.On("Exists", ctx, tnt, srcModel.ID).Return(true, nil).Once() 3506 repo.AssertNotCalled(t, "Update") 3507 repo.AssertNotCalled(t, "Delete") 3508 return repo 3509 }, 3510 LabelRepoFn: func() *automock.LabelRepository { 3511 repo := &automock.LabelRepository{} 3512 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, srcModel.ID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, "id")) 3513 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, destModel.ID).Return(nil, testErr) 3514 3515 return repo 3516 }, 3517 LabelUpsertSvcFn: func() *automock.LabelService { 3518 svc := &automock.LabelService{} 3519 svc.AssertNotCalled(t, "UpsertMultipleLabels") 3520 return svc 3521 }, 3522 Ctx: ctx, 3523 DestinationID: destID, 3524 SourceID: srcID, 3525 ExpectedErrMessage: testErr.Error(), 3526 }, 3527 } 3528 3529 for _, testCase := range testCases { 3530 t.Run(testCase.Name, func(t *testing.T) { 3531 appRepo := testCase.AppRepoFn() 3532 labelRepo := testCase.LabelRepoFn() 3533 labelUpserSvc := testCase.LabelUpsertSvcFn() 3534 svc := application.NewService(nil, nil, appRepo, nil, nil, labelRepo, nil, labelUpserSvc, nil, nil, nil, selfRegDistLabelKey, nil) 3535 3536 // WHEN 3537 destApp, err := svc.Merge(testCase.Ctx, testCase.DestinationID, testCase.SourceID) 3538 3539 // then 3540 if testCase.ExpectedErrMessage == "" { 3541 require.NoError(t, err) 3542 assert.Equal(t, testCase.ExpectedDestinationApplication, destApp) 3543 } else { 3544 require.Error(t, err) 3545 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 3546 } 3547 3548 mock.AssertExpectationsForObjects(t, appRepo, labelRepo, labelUpserSvc) 3549 }) 3550 3551 srcAppLabels = fixApplicationLabels(srcID, labelKey1, labelKey2, labelValue1, "true") 3552 destAppLabels = fixApplicationLabels(srcID, labelKey1, labelKey2, labelValue2, "false") 3553 } 3554 } 3555 3556 func TestService_Get(t *testing.T) { 3557 // GIVEN 3558 testErr := errors.New("Test error") 3559 3560 id := "foo" 3561 3562 desc := "Lorem ipsum" 3563 3564 applicationModel := &model.Application{ 3565 Name: "foo", 3566 Description: &desc, 3567 BaseEntity: &model.BaseEntity{ID: "foo"}, 3568 } 3569 3570 tnt := "tenant" 3571 externalTnt := "external-tnt" 3572 3573 ctx := context.TODO() 3574 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 3575 3576 testCases := []struct { 3577 Name string 3578 RepositoryFn func() *automock.ApplicationRepository 3579 InputID string 3580 ExpectedApplication *model.Application 3581 ExpectedErrMessage string 3582 }{ 3583 { 3584 Name: "Success", 3585 RepositoryFn: func() *automock.ApplicationRepository { 3586 repo := &automock.ApplicationRepository{} 3587 repo.On("GetByID", ctx, tnt, id).Return(applicationModel, nil).Once() 3588 return repo 3589 }, 3590 InputID: id, 3591 ExpectedApplication: applicationModel, 3592 ExpectedErrMessage: "", 3593 }, 3594 { 3595 Name: "Returns error when application retrieval failed", 3596 RepositoryFn: func() *automock.ApplicationRepository { 3597 repo := &automock.ApplicationRepository{} 3598 repo.On("GetByID", ctx, tnt, id).Return(nil, testErr).Once() 3599 return repo 3600 }, 3601 InputID: id, 3602 ExpectedApplication: applicationModel, 3603 ExpectedErrMessage: testErr.Error(), 3604 }, 3605 } 3606 3607 for _, testCase := range testCases { 3608 t.Run(testCase.Name, func(t *testing.T) { 3609 repo := testCase.RepositoryFn() 3610 3611 svc := application.NewService(nil, nil, repo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 3612 3613 // WHEN 3614 app, err := svc.Get(ctx, testCase.InputID) 3615 3616 // then 3617 if testCase.ExpectedErrMessage == "" { 3618 require.NoError(t, err) 3619 assert.Equal(t, testCase.ExpectedApplication, app) 3620 } else { 3621 require.Error(t, err) 3622 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 3623 } 3624 3625 repo.AssertExpectations(t) 3626 }) 3627 } 3628 } 3629 3630 func TestService_GetSystem(t *testing.T) { 3631 // GIVEN 3632 testErr := errors.New("test error") 3633 3634 tnt := "id" 3635 locationID := "loc_id" 3636 virtualHost := "vhost" 3637 filter := labelfilter.NewForKeyWithQuery("scc", fmt.Sprintf("{\"Host\":\"%s\",\"Subaccount\":\"%s\",\"LocationID\":\"%s\"}", virtualHost, tnt, locationID)) 3638 3639 desc := "Lorem ipsum" 3640 3641 applicationModel := &model.Application{ 3642 Name: "foo", 3643 Description: &desc, 3644 BaseEntity: &model.BaseEntity{ID: "foo"}, 3645 } 3646 3647 externalTnt := "external-tnt" 3648 3649 ctx := context.TODO() 3650 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 3651 3652 testCases := []struct { 3653 Name string 3654 Ctx context.Context 3655 RepositoryFn func() *automock.ApplicationRepository 3656 ExpectedApplication *model.Application 3657 ExpectedErrMessage string 3658 }{ 3659 { 3660 Name: "Success", 3661 Ctx: ctx, 3662 RepositoryFn: func() *automock.ApplicationRepository { 3663 repo := &automock.ApplicationRepository{} 3664 repo.On("GetByFilter", ctx, tnt, []*labelfilter.LabelFilter{filter}).Return(applicationModel, nil).Once() 3665 return repo 3666 }, 3667 ExpectedApplication: applicationModel, 3668 }, 3669 { 3670 Name: "Returns error when application retrieval failed", 3671 Ctx: ctx, 3672 RepositoryFn: func() *automock.ApplicationRepository { 3673 repo := &automock.ApplicationRepository{} 3674 repo.On("GetByFilter", ctx, tnt, []*labelfilter.LabelFilter{filter}).Return(nil, testErr).Once() 3675 return repo 3676 }, 3677 ExpectedErrMessage: testErr.Error(), 3678 }, 3679 { 3680 Name: "Returns error when extracting tenant from context", 3681 Ctx: context.TODO(), 3682 RepositoryFn: UnusedApplicationRepository, 3683 ExpectedErrMessage: "while loading tenant from context:", 3684 }, 3685 } 3686 3687 for _, testCase := range testCases { 3688 t.Run(testCase.Name, func(t *testing.T) { 3689 repo := testCase.RepositoryFn() 3690 3691 svc := application.NewService(nil, nil, repo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 3692 3693 // WHEN 3694 app, err := svc.GetSccSystem(testCase.Ctx, "id", locationID, virtualHost) 3695 3696 // then 3697 if testCase.ExpectedErrMessage == "" { 3698 require.NoError(t, err) 3699 assert.Equal(t, testCase.ExpectedApplication, app) 3700 } else { 3701 require.Error(t, err) 3702 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 3703 } 3704 3705 repo.AssertExpectations(t) 3706 }) 3707 } 3708 } 3709 3710 func TestService_List(t *testing.T) { 3711 // GIVEN 3712 testErr := errors.New("Test error") 3713 3714 modelApplications := []*model.Application{ 3715 fixModelApplication("foo", "tenant-foo", "foo", "Lorem Ipsum"), 3716 fixModelApplication("bar", "tenant-bar", "bar", "Lorem Ipsum"), 3717 } 3718 applicationPage := &model.ApplicationPage{ 3719 Data: modelApplications, 3720 TotalCount: len(modelApplications), 3721 PageInfo: &pagination.Page{ 3722 HasNextPage: false, 3723 EndCursor: "end", 3724 StartCursor: "start", 3725 }, 3726 } 3727 3728 first := 2 3729 after := "test" 3730 filter := []*labelfilter.LabelFilter{{Key: ""}} 3731 3732 tnt := "tenant" 3733 externalTnt := "external-tnt" 3734 3735 ctx := context.TODO() 3736 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 3737 3738 testCases := []struct { 3739 Name string 3740 RepositoryFn func() *automock.ApplicationRepository 3741 InputLabelFilters []*labelfilter.LabelFilter 3742 InputPageSize int 3743 ExpectedResult *model.ApplicationPage 3744 ExpectedErrMessage string 3745 }{ 3746 { 3747 Name: "Success", 3748 RepositoryFn: func() *automock.ApplicationRepository { 3749 repo := &automock.ApplicationRepository{} 3750 repo.On("List", ctx, tnt, filter, first, after).Return(applicationPage, nil).Once() 3751 return repo 3752 }, 3753 InputPageSize: first, 3754 InputLabelFilters: filter, 3755 ExpectedResult: applicationPage, 3756 ExpectedErrMessage: "", 3757 }, 3758 { 3759 Name: "Returns error when application listing failed", 3760 RepositoryFn: func() *automock.ApplicationRepository { 3761 repo := &automock.ApplicationRepository{} 3762 repo.On("List", ctx, tnt, filter, first, after).Return(nil, testErr).Once() 3763 return repo 3764 }, 3765 InputPageSize: first, 3766 InputLabelFilters: filter, 3767 ExpectedResult: nil, 3768 ExpectedErrMessage: testErr.Error(), 3769 }, 3770 { 3771 Name: "Returns error when page size is less than 1", 3772 RepositoryFn: UnusedApplicationRepository, 3773 3774 InputPageSize: 0, 3775 InputLabelFilters: filter, 3776 ExpectedResult: nil, 3777 ExpectedErrMessage: "page size must be between 1 and 200", 3778 }, 3779 { 3780 Name: "Returns error when page size is bigger than 200", 3781 RepositoryFn: UnusedApplicationRepository, 3782 3783 InputPageSize: 201, 3784 InputLabelFilters: filter, 3785 ExpectedResult: nil, 3786 ExpectedErrMessage: "page size must be between 1 and 200", 3787 }, 3788 } 3789 3790 for _, testCase := range testCases { 3791 t.Run(testCase.Name, func(t *testing.T) { 3792 repo := testCase.RepositoryFn() 3793 3794 svc := application.NewService(nil, nil, repo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 3795 3796 // WHEN 3797 app, err := svc.List(ctx, testCase.InputLabelFilters, testCase.InputPageSize, after) 3798 3799 // then 3800 if testCase.ExpectedErrMessage == "" { 3801 require.NoError(t, err) 3802 assert.Equal(t, testCase.ExpectedResult, app) 3803 } else { 3804 require.Error(t, err) 3805 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 3806 } 3807 3808 repo.AssertExpectations(t) 3809 }) 3810 } 3811 } 3812 3813 func TestService_ListAll(t *testing.T) { 3814 // GIVEN 3815 testErr := errors.New("Test error") 3816 3817 modelApplications := []*model.Application{ 3818 fixModelApplication("foo", "tenant-foo", "foo", "Lorem Ipsum"), 3819 fixModelApplication("bar", "tenant-bar", "bar", "Lorem Ipsum"), 3820 } 3821 tnt := "tenant" 3822 externalTnt := "external-tnt" 3823 3824 ctxEmpty := context.TODO() 3825 ctx := context.TODO() 3826 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 3827 3828 testCases := []struct { 3829 Name string 3830 Context context.Context 3831 RepositoryFn func() *automock.ApplicationRepository 3832 ExpectedResult []*model.Application 3833 ExpectedErrMessage string 3834 }{ 3835 { 3836 Name: "Success", 3837 Context: ctx, 3838 RepositoryFn: func() *automock.ApplicationRepository { 3839 repo := &automock.ApplicationRepository{} 3840 repo.On("ListAll", ctx, tnt).Return(modelApplications, nil).Once() 3841 return repo 3842 }, 3843 3844 ExpectedResult: modelApplications, 3845 ExpectedErrMessage: "", 3846 }, 3847 { 3848 Name: "Returns error when application listing failed", 3849 Context: ctx, 3850 RepositoryFn: func() *automock.ApplicationRepository { 3851 repo := &automock.ApplicationRepository{} 3852 repo.On("ListAll", ctx, tnt).Return(nil, testErr).Once() 3853 return repo 3854 }, 3855 ExpectedResult: nil, 3856 ExpectedErrMessage: testErr.Error(), 3857 }, 3858 { 3859 Name: "Returns error when tenant is not in the context", 3860 Context: ctxEmpty, 3861 RepositoryFn: func() *automock.ApplicationRepository { 3862 repo := &automock.ApplicationRepository{} 3863 repo.AssertNotCalled(t, "ListAll") 3864 return repo 3865 }, 3866 ExpectedResult: nil, 3867 ExpectedErrMessage: "cannot read tenant from context", 3868 }, 3869 } 3870 3871 for _, testCase := range testCases { 3872 t.Run(testCase.Name, func(t *testing.T) { 3873 // GIVEN 3874 repo := testCase.RepositoryFn() 3875 defer mock.AssertExpectationsForObjects(t, repo) 3876 3877 svc := application.NewService(nil, nil, repo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 3878 3879 // WHEN 3880 app, err := svc.ListAll(testCase.Context) 3881 3882 // THEN 3883 if testCase.ExpectedErrMessage == "" { 3884 require.NoError(t, err) 3885 assert.Equal(t, testCase.ExpectedResult, app) 3886 } else { 3887 require.Error(t, err) 3888 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 3889 } 3890 }) 3891 } 3892 } 3893 3894 func TestService_ListByRuntimeID(t *testing.T) { 3895 runtimeUUID := uuid.New() 3896 testError := errors.New("test error") 3897 tenantUUID := uuid.New() 3898 externalTenantUUID := uuid.New() 3899 ctx := context.TODO() 3900 ctx = tenant.SaveToContext(ctx, tenantUUID.String(), externalTenantUUID.String()) 3901 3902 first := 10 3903 cursor := "test" 3904 scenarios := []interface{}{"Easter", "Christmas", "Winter-Sale"} 3905 scenarioLabel := model.Label{ 3906 ID: uuid.New().String(), 3907 Key: model.ScenariosKey, 3908 Value: scenarios, 3909 } 3910 hidingSelectors := map[string][]string{"foo": {"bar", "baz"}} 3911 3912 applications := []*model.Application{ 3913 fixModelApplication("test1", "tenant-foo", "test1", "test1"), 3914 fixModelApplication("test2", "tenant-foo", "test2", "test2"), 3915 } 3916 applicationPage := fixApplicationPage(applications) 3917 emptyPage := model.ApplicationPage{ 3918 TotalCount: 0, 3919 Data: []*model.Application{}, 3920 PageInfo: &pagination.Page{StartCursor: "", EndCursor: "", HasNextPage: false}} 3921 3922 testCases := []struct { 3923 Name string 3924 Input uuid.UUID 3925 RuntimeRepositoryFn func() *automock.RuntimeRepository 3926 LabelRepositoryFn func() *automock.LabelRepository 3927 AppRepositoryFn func() *automock.ApplicationRepository 3928 ConfigProviderFn func() *automock.ApplicationHideCfgProvider 3929 ExpectedResult *model.ApplicationPage 3930 ExpectedError error 3931 }{ 3932 { 3933 Name: "Success", 3934 Input: runtimeUUID, 3935 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 3936 runtimeRepository := &automock.RuntimeRepository{} 3937 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 3938 Return(true, nil).Once() 3939 return runtimeRepository 3940 }, 3941 LabelRepositoryFn: func() *automock.LabelRepository { 3942 labelRepository := &automock.LabelRepository{} 3943 labelRepository.On("GetByKey", ctx, tenantUUID.String(), model.RuntimeLabelableObject, runtimeUUID.String(), model.ScenariosKey). 3944 Return(&scenarioLabel, nil).Once() 3945 return labelRepository 3946 }, 3947 AppRepositoryFn: func() *automock.ApplicationRepository { 3948 appRepository := &automock.ApplicationRepository{} 3949 appRepository.On("ListByScenarios", ctx, tenantUUID, convertToStringArray(t, scenarios), first, cursor, hidingSelectors). 3950 Return(applicationPage, nil).Once() 3951 return appRepository 3952 }, 3953 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 3954 cfgProvider := &automock.ApplicationHideCfgProvider{} 3955 cfgProvider.On("GetApplicationHideSelectors").Return(hidingSelectors, nil).Once() 3956 return cfgProvider 3957 }, 3958 ExpectedError: nil, 3959 ExpectedResult: applicationPage, 3960 }, 3961 { 3962 Name: "Success when scenarios label not set", 3963 Input: runtimeUUID, 3964 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 3965 runtimeRepository := &automock.RuntimeRepository{} 3966 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 3967 Return(true, nil).Once() 3968 return runtimeRepository 3969 }, 3970 LabelRepositoryFn: func() *automock.LabelRepository { 3971 labelRepository := &automock.LabelRepository{} 3972 labelRepository.On("GetByKey", ctx, tenantUUID.String(), model.RuntimeLabelableObject, runtimeUUID.String(), model.ScenariosKey). 3973 Return(nil, apperrors.NewNotFoundError(resource.Application, "")).Once() 3974 return labelRepository 3975 }, 3976 AppRepositoryFn: UnusedApplicationRepository, 3977 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 3978 cfgProvider := &automock.ApplicationHideCfgProvider{} 3979 return cfgProvider 3980 }, 3981 ExpectedError: nil, 3982 ExpectedResult: &model.ApplicationPage{ 3983 Data: []*model.Application{}, 3984 PageInfo: &pagination.Page{}, 3985 TotalCount: 0, 3986 }, 3987 }, 3988 { 3989 Name: "Return error when checking of runtime existence failed", 3990 Input: runtimeUUID, 3991 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 3992 runtimeRepository := &automock.RuntimeRepository{} 3993 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 3994 Return(false, testError).Once() 3995 return runtimeRepository 3996 }, 3997 LabelRepositoryFn: func() *automock.LabelRepository { 3998 labelRepository := &automock.LabelRepository{} 3999 return labelRepository 4000 }, 4001 AppRepositoryFn: UnusedApplicationRepository, 4002 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 4003 cfgProvider := &automock.ApplicationHideCfgProvider{} 4004 return cfgProvider 4005 }, 4006 ExpectedError: testError, 4007 ExpectedResult: nil, 4008 }, 4009 { 4010 Name: "Return error when runtime not exits", 4011 Input: runtimeUUID, 4012 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 4013 runtimeRepository := &automock.RuntimeRepository{} 4014 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 4015 Return(false, nil).Once() 4016 return runtimeRepository 4017 }, 4018 LabelRepositoryFn: func() *automock.LabelRepository { 4019 labelRepository := &automock.LabelRepository{} 4020 return labelRepository 4021 }, 4022 AppRepositoryFn: UnusedApplicationRepository, 4023 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 4024 cfgProvider := &automock.ApplicationHideCfgProvider{} 4025 return cfgProvider 4026 }, 4027 ExpectedError: errors.New("runtime does not exist"), 4028 ExpectedResult: nil, 4029 }, 4030 { 4031 Name: "Return error when getting runtime scenarios by RuntimeID failed", 4032 Input: runtimeUUID, 4033 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 4034 runtimeRepository := &automock.RuntimeRepository{} 4035 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 4036 Return(true, nil).Once() 4037 return runtimeRepository 4038 }, 4039 LabelRepositoryFn: func() *automock.LabelRepository { 4040 labelRepository := &automock.LabelRepository{} 4041 labelRepository.On("GetByKey", ctx, tenantUUID.String(), model.RuntimeLabelableObject, runtimeUUID.String(), model.ScenariosKey). 4042 Return(nil, testError).Once() 4043 return labelRepository 4044 }, 4045 AppRepositoryFn: UnusedApplicationRepository, 4046 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 4047 cfgProvider := &automock.ApplicationHideCfgProvider{} 4048 return cfgProvider 4049 }, 4050 ExpectedError: testError, 4051 ExpectedResult: nil, 4052 }, 4053 { 4054 Name: "Return error when listing application by scenarios failed", 4055 Input: runtimeUUID, 4056 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 4057 runtimeRepository := &automock.RuntimeRepository{} 4058 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 4059 Return(true, nil).Once() 4060 return runtimeRepository 4061 }, 4062 LabelRepositoryFn: func() *automock.LabelRepository { 4063 labelRepository := &automock.LabelRepository{} 4064 labelRepository.On("GetByKey", ctx, tenantUUID.String(), model.RuntimeLabelableObject, runtimeUUID.String(), model.ScenariosKey). 4065 Return(&scenarioLabel, nil).Once() 4066 return labelRepository 4067 }, 4068 AppRepositoryFn: func() *automock.ApplicationRepository { 4069 appRepository := &automock.ApplicationRepository{} 4070 appRepository.On("ListByScenarios", ctx, tenantUUID, convertToStringArray(t, scenarios), first, cursor, hidingSelectors). 4071 Return(nil, testError).Once() 4072 return appRepository 4073 }, 4074 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 4075 cfgProvider := &automock.ApplicationHideCfgProvider{} 4076 cfgProvider.On("GetApplicationHideSelectors").Return(hidingSelectors, nil).Once() 4077 return cfgProvider 4078 }, 4079 ExpectedError: testError, 4080 ExpectedResult: nil, 4081 }, 4082 { 4083 Name: "Return empty page when runtime is not assigned to any scenario", 4084 Input: runtimeUUID, 4085 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 4086 runtimeRepository := &automock.RuntimeRepository{} 4087 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 4088 Return(true, nil).Once() 4089 return runtimeRepository 4090 }, 4091 LabelRepositoryFn: func() *automock.LabelRepository { 4092 labelRepository := &automock.LabelRepository{} 4093 labelRepository.On("GetByKey", ctx, tenantUUID.String(), model.RuntimeLabelableObject, runtimeUUID.String(), model.ScenariosKey). 4094 Return(&model.Label{ID: uuid.New().String(), Key: model.ScenariosKey, Value: []interface{}{}}, nil).Once() 4095 return labelRepository 4096 }, 4097 AppRepositoryFn: UnusedApplicationRepository, 4098 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 4099 cfgProvider := &automock.ApplicationHideCfgProvider{} 4100 return cfgProvider 4101 }, 4102 ExpectedError: nil, 4103 ExpectedResult: &emptyPage, 4104 }, 4105 { 4106 Name: "Return error when config provider returns error", 4107 Input: runtimeUUID, 4108 RuntimeRepositoryFn: func() *automock.RuntimeRepository { 4109 runtimeRepository := &automock.RuntimeRepository{} 4110 runtimeRepository.On("Exists", ctx, tenantUUID.String(), runtimeUUID.String()). 4111 Return(true, nil).Once() 4112 return runtimeRepository 4113 }, 4114 LabelRepositoryFn: func() *automock.LabelRepository { 4115 labelRepository := &automock.LabelRepository{} 4116 labelRepository.On("GetByKey", ctx, tenantUUID.String(), model.RuntimeLabelableObject, runtimeUUID.String(), model.ScenariosKey). 4117 Return(&scenarioLabel, nil).Once() 4118 return labelRepository 4119 }, 4120 AppRepositoryFn: UnusedApplicationRepository, 4121 ConfigProviderFn: func() *automock.ApplicationHideCfgProvider { 4122 cfgProvider := &automock.ApplicationHideCfgProvider{} 4123 cfgProvider.On("GetApplicationHideSelectors").Return(nil, testError).Once() 4124 return cfgProvider 4125 }, 4126 ExpectedError: testError, 4127 ExpectedResult: nil, 4128 }, 4129 } 4130 4131 for _, testCase := range testCases { 4132 t.Run(testCase.Name, func(t *testing.T) { 4133 // GIVEN 4134 runtimeRepository := testCase.RuntimeRepositoryFn() 4135 labelRepository := testCase.LabelRepositoryFn() 4136 appRepository := testCase.AppRepositoryFn() 4137 cfgProvider := testCase.ConfigProviderFn() 4138 svc := application.NewService(nil, cfgProvider, appRepository, nil, runtimeRepository, labelRepository, nil, nil, nil, nil, nil, "", nil) 4139 4140 // WHEN 4141 results, err := svc.ListByRuntimeID(ctx, testCase.Input, first, cursor) 4142 4143 // THEN 4144 if testCase.ExpectedError != nil { 4145 require.Error(t, err) 4146 assert.Contains(t, err.Error(), testCase.ExpectedError.Error()) 4147 } else { 4148 logrus.Info(err) 4149 require.NoError(t, err) 4150 } 4151 assert.Equal(t, testCase.ExpectedResult, results) 4152 mock.AssertExpectationsForObjects(t, runtimeRepository, labelRepository, appRepository, cfgProvider) 4153 }) 4154 } 4155 } 4156 4157 func TestService_ListBySCC(t *testing.T) { 4158 // GIVEN 4159 testErr := errors.New("test error") 4160 4161 tnt := "tenant" 4162 4163 app1ID := "foo" 4164 app2ID := "bar" 4165 4166 app1 := fixModelApplication(app1ID, tnt, "foo", "Lorem Ipsum") 4167 app2 := fixModelApplication(app2ID, tnt, "bar", "Lorem Ipsum") 4168 applications := []*model.Application{app1, app2} 4169 4170 labelValue := stringPtr("{\"locationId\":\"locationId\", \"subaccount\":\"tenant\"}") 4171 4172 label1 := &model.Label{ 4173 ObjectID: app1ID, 4174 Value: labelValue, 4175 } 4176 4177 label2 := &model.Label{ 4178 ObjectID: app2ID, 4179 Value: labelValue, 4180 } 4181 4182 applicationsWitLabel := []*model.ApplicationWithLabel{ 4183 { 4184 App: app1, 4185 SccLabel: label1, 4186 }, 4187 { 4188 App: app2, 4189 SccLabel: label2, 4190 }, 4191 } 4192 4193 filter := &labelfilter.LabelFilter{Key: "scc", Query: stringPtr("{\"locationId\":\"locationId\", \"subaccount\":\"tenant\"}")} 4194 4195 externalTnt := "external-tnt" 4196 4197 ctx := context.TODO() 4198 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4199 4200 testCases := []struct { 4201 Name string 4202 Ctx context.Context 4203 RepositoryFn func() *automock.ApplicationRepository 4204 LabelRepositoryFn func() *automock.LabelRepository 4205 InputLabelFilter *labelfilter.LabelFilter 4206 ExpectedResult []*model.ApplicationWithLabel 4207 ExpectedErrMessage string 4208 }{ 4209 { 4210 Name: "Success", 4211 Ctx: ctx, 4212 RepositoryFn: func() *automock.ApplicationRepository { 4213 repo := &automock.ApplicationRepository{} 4214 repo.On("ListAllByFilter", ctx, tnt, []*labelfilter.LabelFilter{filter}).Return(applications, nil).Once() 4215 return repo 4216 }, 4217 LabelRepositoryFn: func() *automock.LabelRepository { 4218 repo := &automock.LabelRepository{} 4219 repo.On("ListGlobalByKeyAndObjects", ctx, model.ApplicationLabelableObject, []string{app1ID, app2ID}, "scc").Return([]*model.Label{label1, label2}, nil) 4220 return repo 4221 }, 4222 InputLabelFilter: filter, 4223 ExpectedResult: applicationsWitLabel, 4224 ExpectedErrMessage: "", 4225 }, 4226 { 4227 Name: "Success when no apps matching the filter are found", 4228 Ctx: ctx, 4229 RepositoryFn: func() *automock.ApplicationRepository { 4230 repo := &automock.ApplicationRepository{} 4231 repo.On("ListAllByFilter", ctx, tnt, []*labelfilter.LabelFilter{filter}).Return([]*model.Application{}, nil).Once() 4232 return repo 4233 }, 4234 LabelRepositoryFn: UnusedLabelRepository, 4235 InputLabelFilter: filter, 4236 ExpectedResult: []*model.ApplicationWithLabel{}, 4237 ExpectedErrMessage: "", 4238 }, 4239 { 4240 Name: "Returns error when failed to list labels for applications", 4241 Ctx: ctx, 4242 RepositoryFn: func() *automock.ApplicationRepository { 4243 repo := &automock.ApplicationRepository{} 4244 repo.On("ListAllByFilter", ctx, tnt, []*labelfilter.LabelFilter{filter}).Return(applications, nil).Once() 4245 return repo 4246 }, 4247 LabelRepositoryFn: func() *automock.LabelRepository { 4248 repo := &automock.LabelRepository{} 4249 repo.On("ListGlobalByKeyAndObjects", ctx, model.ApplicationLabelableObject, []string{app1ID, app2ID}, "scc").Return(nil, testErr) 4250 return repo 4251 }, 4252 InputLabelFilter: filter, 4253 ExpectedResult: nil, 4254 ExpectedErrMessage: "while getting labels with key scc for applications with IDs:", 4255 }, 4256 { 4257 Name: "Returns error when application listing failed", 4258 Ctx: ctx, 4259 RepositoryFn: func() *automock.ApplicationRepository { 4260 repo := &automock.ApplicationRepository{} 4261 repo.On("ListAllByFilter", ctx, tnt, []*labelfilter.LabelFilter{filter}).Return(nil, testErr).Once() 4262 return repo 4263 }, 4264 LabelRepositoryFn: UnusedLabelRepository, 4265 InputLabelFilter: filter, 4266 ExpectedResult: nil, 4267 ExpectedErrMessage: testErr.Error(), 4268 }, 4269 { 4270 Name: "Returns error when extracting tenant from context", 4271 Ctx: context.TODO(), 4272 RepositoryFn: UnusedApplicationRepository, 4273 4274 LabelRepositoryFn: UnusedLabelRepository, 4275 ExpectedErrMessage: "while loading tenant from context:", 4276 }, 4277 } 4278 4279 for _, testCase := range testCases { 4280 t.Run(testCase.Name, func(t *testing.T) { 4281 appRepo := testCase.RepositoryFn() 4282 labelRepo := testCase.LabelRepositoryFn() 4283 svc := application.NewService(nil, nil, appRepo, nil, nil, labelRepo, nil, nil, nil, nil, nil, "", nil) 4284 4285 // WHEN 4286 app, err := svc.ListBySCC(testCase.Ctx, filter) 4287 4288 // then 4289 if testCase.ExpectedErrMessage == "" { 4290 require.NoError(t, err) 4291 assert.Equal(t, testCase.ExpectedResult, app) 4292 } else { 4293 require.Error(t, err) 4294 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 4295 } 4296 4297 appRepo.AssertExpectations(t) 4298 }) 4299 } 4300 } 4301 4302 func TestService_ListSCCs(t *testing.T) { 4303 // GIVEN 4304 testErr := errors.New("test error") 4305 4306 tnt := "tenant" 4307 4308 key := "scc" 4309 4310 locationID1 := "locationID1" 4311 locationID2 := "locationID2" 4312 subaccount1 := "subaccount1" 4313 subaccount2 := "subaccount2" 4314 4315 labelValue1 := map[string]interface{}{"LocationID": locationID1, "Subaccount": subaccount1} 4316 labelValue2 := map[string]interface{}{"LocationID": locationID2, "Subaccount": subaccount2} 4317 4318 labels := []*model.Label{ 4319 {Value: labelValue1}, 4320 {Value: labelValue2}, 4321 } 4322 4323 sccs := []*model.SccMetadata{ 4324 { 4325 Subaccount: subaccount1, 4326 LocationID: locationID1, 4327 }, 4328 { 4329 Subaccount: subaccount2, 4330 LocationID: locationID2, 4331 }, 4332 } 4333 4334 filter := &labelfilter.LabelFilter{Key: "scc", Query: stringPtr("{\"locationId\":\"locationId\", \"subaccount\":\"tenant\"}")} 4335 4336 externalTnt := "external-tnt" 4337 4338 ctx := context.TODO() 4339 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4340 4341 testCases := []struct { 4342 Name string 4343 Ctx context.Context 4344 RepositoryFn func() *automock.LabelRepository 4345 InputLabelFilter *labelfilter.LabelFilter 4346 ExpectedResult []*model.SccMetadata 4347 ExpectedErrMessage string 4348 }{ 4349 { 4350 Name: "Success", 4351 Ctx: ctx, 4352 RepositoryFn: func() *automock.LabelRepository { 4353 repo := &automock.LabelRepository{} 4354 repo.On("ListGlobalByKey", ctx, key).Return(labels, nil).Once() 4355 return repo 4356 }, 4357 InputLabelFilter: filter, 4358 ExpectedResult: sccs, 4359 ExpectedErrMessage: "", 4360 }, 4361 { 4362 Name: "Returns error when labels listing failed", 4363 Ctx: ctx, 4364 RepositoryFn: func() *automock.LabelRepository { 4365 repo := &automock.LabelRepository{} 4366 repo.On("ListGlobalByKey", ctx, key).Return(nil, testErr).Once() 4367 return repo 4368 }, 4369 InputLabelFilter: filter, 4370 ExpectedResult: nil, 4371 ExpectedErrMessage: testErr.Error(), 4372 }, 4373 } 4374 4375 for _, testCase := range testCases { 4376 t.Run(testCase.Name, func(t *testing.T) { 4377 repo := testCase.RepositoryFn() 4378 4379 svc := application.NewService(nil, nil, nil, nil, nil, repo, nil, nil, nil, nil, nil, "", nil) 4380 4381 // WHEN 4382 app, err := svc.ListSCCs(testCase.Ctx) 4383 4384 // then 4385 if testCase.ExpectedErrMessage == "" { 4386 require.NoError(t, err) 4387 assert.Equal(t, testCase.ExpectedResult, app) 4388 } else { 4389 require.Error(t, err) 4390 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 4391 } 4392 4393 repo.AssertExpectations(t) 4394 }) 4395 } 4396 } 4397 4398 func TestService_Exist(t *testing.T) { 4399 tnt := "tenant" 4400 externalTnt := "external-tnt" 4401 4402 ctx := context.TODO() 4403 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4404 testError := errors.New("Test error") 4405 4406 applicationID := "id" 4407 4408 testCases := []struct { 4409 Name string 4410 RepositoryFn func() *automock.ApplicationRepository 4411 InputApplicationID string 4412 ExptectedValue bool 4413 ExpectedError error 4414 }{ 4415 { 4416 Name: "Application exits", 4417 RepositoryFn: func() *automock.ApplicationRepository { 4418 repo := &automock.ApplicationRepository{} 4419 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil) 4420 return repo 4421 }, 4422 InputApplicationID: applicationID, 4423 ExptectedValue: true, 4424 ExpectedError: nil, 4425 }, 4426 { 4427 Name: "Application not exits", 4428 RepositoryFn: func() *automock.ApplicationRepository { 4429 repo := &automock.ApplicationRepository{} 4430 repo.On("Exists", ctx, tnt, applicationID).Return(false, nil) 4431 return repo 4432 }, 4433 InputApplicationID: applicationID, 4434 ExptectedValue: false, 4435 ExpectedError: nil, 4436 }, 4437 { 4438 Name: "Returns error", 4439 RepositoryFn: func() *automock.ApplicationRepository { 4440 repo := &automock.ApplicationRepository{} 4441 repo.On("Exists", ctx, tnt, applicationID).Return(false, testError) 4442 return repo 4443 }, 4444 InputApplicationID: applicationID, 4445 ExptectedValue: false, 4446 ExpectedError: testError, 4447 }, 4448 } 4449 4450 for _, testCase := range testCases { 4451 t.Run(testCase.Name, func(t *testing.T) { 4452 // GIVEN 4453 appRepo := testCase.RepositoryFn() 4454 svc := application.NewService(nil, nil, appRepo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 4455 4456 // WHEN 4457 value, err := svc.Exist(ctx, testCase.InputApplicationID) 4458 4459 // THEN 4460 if testCase.ExpectedError != nil { 4461 require.Error(t, err) 4462 assert.Contains(t, err.Error(), testCase.ExpectedError.Error()) 4463 } else { 4464 require.Nil(t, err) 4465 } 4466 4467 assert.Equal(t, testCase.ExptectedValue, value) 4468 appRepo.AssertExpectations(t) 4469 }) 4470 } 4471 } 4472 4473 func TestService_SetLabel(t *testing.T) { 4474 // GIVEN 4475 tnt := "tenant" 4476 externalTnt := "external-tnt" 4477 4478 ctx := context.TODO() 4479 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4480 4481 testErr := errors.New("Test error") 4482 4483 applicationID := "foo" 4484 4485 label := &model.LabelInput{ 4486 Key: "key", 4487 Value: []string{"value1"}, 4488 ObjectID: applicationID, 4489 ObjectType: model.ApplicationLabelableObject, 4490 } 4491 4492 newScenario := "new-scenario" 4493 extraScenario := "unnecessary-scenario" 4494 scenarioLabel := &model.LabelInput{ 4495 Key: model.ScenariosKey, 4496 Value: []interface{}{testScenario, newScenario}, 4497 ObjectID: applicationID, 4498 ObjectType: model.ApplicationLabelableObject, 4499 } 4500 4501 testCases := []struct { 4502 Name string 4503 RepositoryFn func() *automock.ApplicationRepository 4504 LabelRepoFn func() *automock.LabelRepository 4505 LabelServiceFn func() *automock.LabelService 4506 FormationServiceFn func() *automock.FormationService 4507 InputApplicationID string 4508 InputLabel *model.LabelInput 4509 ExpectedErrMessage string 4510 }{ 4511 { 4512 Name: "Success", 4513 RepositoryFn: func() *automock.ApplicationRepository { 4514 repo := &automock.ApplicationRepository{} 4515 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4516 4517 return repo 4518 }, 4519 LabelRepoFn: func() *automock.LabelRepository { 4520 svc := &automock.LabelRepository{} 4521 return svc 4522 }, 4523 LabelServiceFn: func() *automock.LabelService { 4524 svc := &automock.LabelService{} 4525 svc.On("UpsertLabel", ctx, tnt, label).Return(nil).Once() 4526 return svc 4527 }, 4528 FormationServiceFn: UnusedFormationService, 4529 InputApplicationID: applicationID, 4530 InputLabel: label, 4531 ExpectedErrMessage: "", 4532 }, 4533 { 4534 Name: "Returns error when label set failed", 4535 RepositoryFn: func() *automock.ApplicationRepository { 4536 repo := &automock.ApplicationRepository{} 4537 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4538 4539 return repo 4540 }, 4541 LabelRepoFn: func() *automock.LabelRepository { 4542 svc := &automock.LabelRepository{} 4543 return svc 4544 }, 4545 LabelServiceFn: func() *automock.LabelService { 4546 svc := &automock.LabelService{} 4547 svc.On("UpsertLabel", ctx, tnt, label).Return(testErr).Once() 4548 return svc 4549 }, 4550 FormationServiceFn: UnusedFormationService, 4551 InputApplicationID: applicationID, 4552 InputLabel: label, 4553 ExpectedErrMessage: testErr.Error(), 4554 }, 4555 { 4556 Name: "Returns error when application retrieval failed", 4557 RepositoryFn: func() *automock.ApplicationRepository { 4558 repo := &automock.ApplicationRepository{} 4559 repo.On("Exists", ctx, tnt, applicationID).Return(false, testErr).Once() 4560 4561 return repo 4562 }, 4563 LabelRepoFn: func() *automock.LabelRepository { 4564 svc := &automock.LabelRepository{} 4565 return svc 4566 }, 4567 LabelServiceFn: UnusedLabelService, 4568 FormationServiceFn: UnusedFormationService, 4569 InputApplicationID: applicationID, 4570 InputLabel: label, 4571 ExpectedErrMessage: testErr.Error(), 4572 }, 4573 { 4574 Name: "Success when all calls to formation service succeed", 4575 RepositoryFn: func() *automock.ApplicationRepository { 4576 repo := &automock.ApplicationRepository{} 4577 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4578 4579 return repo 4580 }, 4581 LabelRepoFn: func() *automock.LabelRepository { 4582 repo := &automock.LabelRepository{} 4583 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(&model.Label{ 4584 Tenant: &tnt, 4585 Key: model.ScenariosKey, 4586 Value: []interface{}{testScenario, extraScenario}, 4587 ObjectID: applicationID, 4588 ObjectType: model.ApplicationLabelableObject, 4589 Version: 0, 4590 }, nil) 4591 return repo 4592 }, 4593 LabelServiceFn: UnusedLabelService, 4594 FormationServiceFn: func() *automock.FormationService { 4595 svc := &automock.FormationService{} 4596 svc.On("AssignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: newScenario}).Return(nil, nil).Once() 4597 svc.On("UnassignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: extraScenario}).Return(nil, nil).Once() 4598 return svc 4599 }, 4600 InputApplicationID: applicationID, 4601 InputLabel: scenarioLabel, 4602 ExpectedErrMessage: "", 4603 }, 4604 { 4605 Name: "Error when call to AssignFormation fails", 4606 RepositoryFn: func() *automock.ApplicationRepository { 4607 repo := &automock.ApplicationRepository{} 4608 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4609 4610 return repo 4611 }, 4612 LabelRepoFn: func() *automock.LabelRepository { 4613 repo := &automock.LabelRepository{} 4614 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(&model.Label{ 4615 Tenant: &tnt, 4616 Key: model.ScenariosKey, 4617 Value: []interface{}{testScenario, extraScenario}, 4618 ObjectID: applicationID, 4619 ObjectType: model.ApplicationLabelableObject, 4620 Version: 0, 4621 }, nil) 4622 return repo 4623 }, 4624 LabelServiceFn: UnusedLabelService, 4625 FormationServiceFn: func() *automock.FormationService { 4626 svc := &automock.FormationService{} 4627 svc.On("AssignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: newScenario}).Return(nil, testErr).Once() 4628 return svc 4629 }, 4630 InputApplicationID: applicationID, 4631 InputLabel: scenarioLabel, 4632 ExpectedErrMessage: testErr.Error(), 4633 }, 4634 { 4635 Name: "Error when call to UnassignFormation fails", 4636 RepositoryFn: func() *automock.ApplicationRepository { 4637 repo := &automock.ApplicationRepository{} 4638 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4639 4640 return repo 4641 }, 4642 LabelRepoFn: func() *automock.LabelRepository { 4643 repo := &automock.LabelRepository{} 4644 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(&model.Label{ 4645 Tenant: &tnt, 4646 Key: model.ScenariosKey, 4647 Value: []interface{}{testScenario, extraScenario}, 4648 ObjectID: applicationID, 4649 ObjectType: model.ApplicationLabelableObject, 4650 Version: 0, 4651 }, nil) 4652 return repo 4653 }, 4654 LabelServiceFn: UnusedLabelService, 4655 FormationServiceFn: func() *automock.FormationService { 4656 svc := &automock.FormationService{} 4657 svc.On("AssignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: newScenario}).Return(nil, nil).Once() 4658 svc.On("UnassignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: extraScenario}).Return(nil, testErr).Once() 4659 return svc 4660 }, 4661 InputApplicationID: applicationID, 4662 InputLabel: scenarioLabel, 4663 ExpectedErrMessage: testErr.Error(), 4664 }, 4665 { 4666 Name: "Success when scenario label does not exist", 4667 RepositoryFn: func() *automock.ApplicationRepository { 4668 repo := &automock.ApplicationRepository{} 4669 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4670 4671 return repo 4672 }, 4673 LabelRepoFn: func() *automock.LabelRepository { 4674 repo := &automock.LabelRepository{} 4675 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(nil, apperrors.NewNotFoundError(resource.Label, applicationID)) 4676 return repo 4677 }, 4678 LabelServiceFn: UnusedLabelService, 4679 FormationServiceFn: func() *automock.FormationService { 4680 svc := &automock.FormationService{} 4681 svc.On("AssignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 4682 svc.On("AssignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: newScenario}).Return(nil, nil).Once() 4683 return svc 4684 }, 4685 InputApplicationID: applicationID, 4686 InputLabel: scenarioLabel, 4687 ExpectedErrMessage: "", 4688 }, 4689 { 4690 Name: "Error when GetByKey call fails", 4691 RepositoryFn: func() *automock.ApplicationRepository { 4692 repo := &automock.ApplicationRepository{} 4693 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4694 4695 return repo 4696 }, 4697 LabelRepoFn: func() *automock.LabelRepository { 4698 repo := &automock.LabelRepository{} 4699 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(nil, testErr) 4700 return repo 4701 }, 4702 LabelServiceFn: UnusedLabelService, 4703 FormationServiceFn: UnusedFormationService, 4704 InputApplicationID: applicationID, 4705 InputLabel: scenarioLabel, 4706 ExpectedErrMessage: testErr.Error(), 4707 }, 4708 } 4709 4710 for _, testCase := range testCases { 4711 t.Run(testCase.Name, func(t *testing.T) { 4712 repo := testCase.RepositoryFn() 4713 labelRepo := testCase.LabelRepoFn() 4714 labelSvc := testCase.LabelServiceFn() 4715 formationSvc := testCase.FormationServiceFn() 4716 4717 svc := application.NewService(nil, nil, repo, nil, nil, labelRepo, nil, labelSvc, nil, nil, formationSvc, "", nil) 4718 4719 // WHEN 4720 err := svc.SetLabel(ctx, testCase.InputLabel) 4721 4722 // then 4723 if testCase.ExpectedErrMessage == "" { 4724 require.NoError(t, err) 4725 } else { 4726 require.Error(t, err) 4727 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 4728 } 4729 4730 mock.AssertExpectationsForObjects(t, repo, labelRepo, labelSvc, formationSvc) 4731 }) 4732 } 4733 } 4734 4735 func TestService_GetLabel(t *testing.T) { 4736 // GIVEN 4737 tnt := "tenant" 4738 externalTnt := "external-tnt" 4739 4740 ctx := context.TODO() 4741 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4742 4743 testErr := errors.New("Test error") 4744 4745 applicationID := "foo" 4746 labelKey := "key" 4747 labelValue := []string{"value1"} 4748 4749 label := &model.LabelInput{ 4750 Key: labelKey, 4751 Value: labelValue, 4752 ObjectID: applicationID, 4753 ObjectType: model.ApplicationLabelableObject, 4754 } 4755 4756 modelLabel := &model.Label{ 4757 ID: "5d23d9d9-3d04-4fa9-95e6-d22e1ae62c11", 4758 Tenant: str.Ptr(tnt), 4759 Key: labelKey, 4760 Value: labelValue, 4761 ObjectID: applicationID, 4762 ObjectType: model.ApplicationLabelableObject, 4763 } 4764 4765 testCases := []struct { 4766 Name string 4767 RepositoryFn func() *automock.ApplicationRepository 4768 LabelRepositoryFn func() *automock.LabelRepository 4769 InputApplicationID string 4770 InputLabel *model.LabelInput 4771 ExpectedLabel *model.Label 4772 ExpectedErrMessage string 4773 }{ 4774 { 4775 Name: "Success", 4776 RepositoryFn: func() *automock.ApplicationRepository { 4777 repo := &automock.ApplicationRepository{} 4778 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4779 return repo 4780 }, 4781 LabelRepositoryFn: func() *automock.LabelRepository { 4782 repo := &automock.LabelRepository{} 4783 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, labelKey).Return(modelLabel, nil).Once() 4784 return repo 4785 }, 4786 InputApplicationID: applicationID, 4787 InputLabel: label, 4788 ExpectedLabel: modelLabel, 4789 ExpectedErrMessage: "", 4790 }, 4791 { 4792 Name: "Returns error when label receiving failed", 4793 RepositoryFn: func() *automock.ApplicationRepository { 4794 repo := &automock.ApplicationRepository{} 4795 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4796 4797 return repo 4798 }, 4799 LabelRepositoryFn: func() *automock.LabelRepository { 4800 repo := &automock.LabelRepository{} 4801 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, labelKey).Return(nil, testErr).Once() 4802 return repo 4803 }, 4804 InputApplicationID: applicationID, 4805 InputLabel: label, 4806 ExpectedLabel: nil, 4807 ExpectedErrMessage: testErr.Error(), 4808 }, 4809 { 4810 Name: "Returns error when application doesn't exist", 4811 RepositoryFn: func() *automock.ApplicationRepository { 4812 repo := &automock.ApplicationRepository{} 4813 repo.On("Exists", ctx, tnt, applicationID).Return(false, testErr).Once() 4814 4815 return repo 4816 }, 4817 LabelRepositoryFn: UnusedLabelRepository, 4818 InputApplicationID: applicationID, 4819 InputLabel: label, 4820 ExpectedErrMessage: testErr.Error(), 4821 }, 4822 } 4823 4824 for _, testCase := range testCases { 4825 t.Run(testCase.Name, func(t *testing.T) { 4826 repo := testCase.RepositoryFn() 4827 labelRepo := testCase.LabelRepositoryFn() 4828 svc := application.NewService(nil, nil, repo, nil, nil, labelRepo, nil, nil, nil, nil, nil, "", nil) 4829 4830 // WHEN 4831 l, err := svc.GetLabel(ctx, testCase.InputApplicationID, testCase.InputLabel.Key) 4832 4833 // then 4834 if testCase.ExpectedErrMessage == "" { 4835 require.NoError(t, err) 4836 assert.Equal(t, l, testCase.ExpectedLabel) 4837 } else { 4838 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 4839 } 4840 4841 repo.AssertExpectations(t) 4842 labelRepo.AssertExpectations(t) 4843 }) 4844 } 4845 } 4846 4847 func TestService_ListLabel(t *testing.T) { 4848 // GIVEN 4849 tnt := "tenant" 4850 externalTnt := "external-tnt" 4851 4852 ctx := context.TODO() 4853 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4854 4855 testErr := errors.New("Test error") 4856 4857 applicationID := "foo" 4858 labelKey := "key" 4859 labelValue := []string{"value1"} 4860 4861 label := &model.LabelInput{ 4862 Key: labelKey, 4863 Value: labelValue, 4864 ObjectID: applicationID, 4865 ObjectType: model.ApplicationLabelableObject, 4866 } 4867 4868 modelLabel := &model.Label{ 4869 ID: "5d23d9d9-3d04-4fa9-95e6-d22e1ae62c11", 4870 Tenant: str.Ptr(tnt), 4871 Key: labelKey, 4872 Value: labelValue, 4873 ObjectID: applicationID, 4874 ObjectType: model.ApplicationLabelableObject, 4875 } 4876 4877 labels := map[string]*model.Label{"first": modelLabel, "second": modelLabel} 4878 testCases := []struct { 4879 Name string 4880 RepositoryFn func() *automock.ApplicationRepository 4881 LabelRepositoryFn func() *automock.LabelRepository 4882 InputApplicationID string 4883 InputLabel *model.LabelInput 4884 ExpectedOutput map[string]*model.Label 4885 ExpectedErrMessage string 4886 }{ 4887 { 4888 Name: "Success", 4889 RepositoryFn: func() *automock.ApplicationRepository { 4890 repo := &automock.ApplicationRepository{} 4891 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4892 return repo 4893 }, 4894 LabelRepositoryFn: func() *automock.LabelRepository { 4895 repo := &automock.LabelRepository{} 4896 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, applicationID).Return(labels, nil).Once() 4897 return repo 4898 }, 4899 InputApplicationID: applicationID, 4900 InputLabel: label, 4901 ExpectedOutput: labels, 4902 ExpectedErrMessage: "", 4903 }, 4904 { 4905 Name: "Returns error when labels receiving failed", 4906 RepositoryFn: func() *automock.ApplicationRepository { 4907 repo := &automock.ApplicationRepository{} 4908 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4909 4910 return repo 4911 }, 4912 LabelRepositoryFn: func() *automock.LabelRepository { 4913 repo := &automock.LabelRepository{} 4914 repo.On("ListForObject", ctx, tnt, model.ApplicationLabelableObject, applicationID).Return(nil, testErr).Once() 4915 return repo 4916 }, 4917 InputApplicationID: applicationID, 4918 InputLabel: label, 4919 ExpectedOutput: nil, 4920 ExpectedErrMessage: testErr.Error(), 4921 }, 4922 { 4923 Name: "Returns error when application doesn't exist", 4924 RepositoryFn: func() *automock.ApplicationRepository { 4925 repo := &automock.ApplicationRepository{} 4926 repo.On("Exists", ctx, tnt, applicationID).Return(false, testErr).Once() 4927 4928 return repo 4929 }, 4930 LabelRepositoryFn: UnusedLabelRepository, 4931 InputApplicationID: applicationID, 4932 InputLabel: label, 4933 ExpectedErrMessage: testErr.Error(), 4934 }, 4935 } 4936 4937 for _, testCase := range testCases { 4938 t.Run(testCase.Name, func(t *testing.T) { 4939 repo := testCase.RepositoryFn() 4940 labelRepo := testCase.LabelRepositoryFn() 4941 svc := application.NewService(nil, nil, repo, nil, nil, labelRepo, nil, nil, nil, nil, nil, "", nil) 4942 4943 // WHEN 4944 l, err := svc.ListLabels(ctx, testCase.InputApplicationID) 4945 4946 // then 4947 if testCase.ExpectedErrMessage == "" { 4948 require.NoError(t, err) 4949 assert.Equal(t, l, testCase.ExpectedOutput) 4950 } else { 4951 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 4952 } 4953 4954 repo.AssertExpectations(t) 4955 labelRepo.AssertExpectations(t) 4956 }) 4957 } 4958 } 4959 4960 func TestService_DeleteLabel(t *testing.T) { 4961 // GIVEN 4962 tnt := "tenant" 4963 externalTnt := "external-tnt" 4964 4965 ctx := context.TODO() 4966 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 4967 4968 testErr := errors.New("Test error") 4969 4970 applicationID := "foo" 4971 4972 labelKey := "key" 4973 4974 testCases := []struct { 4975 Name string 4976 RepositoryFn func() *automock.ApplicationRepository 4977 LabelRepositoryFn func() *automock.LabelRepository 4978 FormationServiceFn func() *automock.FormationService 4979 InputApplicationID string 4980 InputKey string 4981 ExpectedErrMessage string 4982 }{ 4983 { 4984 Name: "Success", 4985 RepositoryFn: func() *automock.ApplicationRepository { 4986 repo := &automock.ApplicationRepository{} 4987 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 4988 return repo 4989 }, 4990 LabelRepositoryFn: func() *automock.LabelRepository { 4991 repo := &automock.LabelRepository{} 4992 repo.On("Delete", ctx, tnt, model.ApplicationLabelableObject, applicationID, labelKey).Return(nil).Once() 4993 return repo 4994 }, 4995 FormationServiceFn: UnusedFormationService, 4996 InputApplicationID: applicationID, 4997 InputKey: labelKey, 4998 ExpectedErrMessage: "", 4999 }, 5000 { 5001 Name: "Returns error when label delete failed", 5002 RepositoryFn: func() *automock.ApplicationRepository { 5003 repo := &automock.ApplicationRepository{} 5004 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 5005 return repo 5006 }, 5007 LabelRepositoryFn: func() *automock.LabelRepository { 5008 repo := &automock.LabelRepository{} 5009 repo.On("Delete", ctx, tnt, model.ApplicationLabelableObject, applicationID, labelKey).Return(testErr).Once() 5010 return repo 5011 }, 5012 FormationServiceFn: UnusedFormationService, 5013 InputApplicationID: applicationID, 5014 InputKey: labelKey, 5015 ExpectedErrMessage: testErr.Error(), 5016 }, 5017 { 5018 Name: "Returns error when application retrieval failed", 5019 RepositoryFn: func() *automock.ApplicationRepository { 5020 repo := &automock.ApplicationRepository{} 5021 repo.On("Exists", ctx, tnt, applicationID).Return(false, testErr).Once() 5022 return repo 5023 }, 5024 LabelRepositoryFn: UnusedLabelRepository, 5025 FormationServiceFn: UnusedFormationService, 5026 InputApplicationID: applicationID, 5027 InputKey: labelKey, 5028 ExpectedErrMessage: testErr.Error(), 5029 }, 5030 { 5031 Name: "Returns error when application does not exist", 5032 RepositoryFn: func() *automock.ApplicationRepository { 5033 repo := &automock.ApplicationRepository{} 5034 repo.On("Exists", ctx, tnt, applicationID).Return(false, nil).Once() 5035 return repo 5036 }, 5037 LabelRepositoryFn: UnusedLabelRepository, 5038 FormationServiceFn: UnusedFormationService, 5039 InputApplicationID: applicationID, 5040 InputKey: labelKey, 5041 ExpectedErrMessage: fmt.Sprintf("application with ID %s doesn't exist", applicationID), 5042 }, 5043 { 5044 Name: "Success when deleting formations from scenario label", 5045 RepositoryFn: func() *automock.ApplicationRepository { 5046 repo := &automock.ApplicationRepository{} 5047 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 5048 return repo 5049 }, 5050 LabelRepositoryFn: func() *automock.LabelRepository { 5051 repo := &automock.LabelRepository{} 5052 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(&model.Label{Value: []interface{}{testScenario}}, nil).Once() 5053 return repo 5054 }, 5055 FormationServiceFn: func() *automock.FormationService { 5056 service := &automock.FormationService{} 5057 service.On("UnassignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, nil).Once() 5058 return service 5059 }, 5060 InputApplicationID: applicationID, 5061 InputKey: model.ScenariosKey, 5062 ExpectedErrMessage: "", 5063 }, 5064 { 5065 Name: "Returns error when UnassignFormation fails", 5066 RepositoryFn: func() *automock.ApplicationRepository { 5067 repo := &automock.ApplicationRepository{} 5068 repo.On("Exists", ctx, tnt, applicationID).Return(true, nil).Once() 5069 return repo 5070 }, 5071 LabelRepositoryFn: func() *automock.LabelRepository { 5072 repo := &automock.LabelRepository{} 5073 repo.On("GetByKey", ctx, tnt, model.ApplicationLabelableObject, applicationID, model.ScenariosKey).Return(&model.Label{Value: []interface{}{testScenario}}, nil).Once() 5074 return repo 5075 }, 5076 FormationServiceFn: func() *automock.FormationService { 5077 service := &automock.FormationService{} 5078 service.On("UnassignFormation", ctx, tnt, applicationID, graphql.FormationObjectTypeApplication, model.Formation{Name: testScenario}).Return(nil, testErr).Once() 5079 return service 5080 }, 5081 InputApplicationID: applicationID, 5082 InputKey: model.ScenariosKey, 5083 ExpectedErrMessage: testErr.Error(), 5084 }, 5085 } 5086 5087 for _, testCase := range testCases { 5088 t.Run(testCase.Name, func(t *testing.T) { 5089 repo := testCase.RepositoryFn() 5090 labelRepo := testCase.LabelRepositoryFn() 5091 formationSvc := testCase.FormationServiceFn() 5092 svc := application.NewService(nil, nil, repo, nil, nil, labelRepo, nil, nil, nil, nil, formationSvc, "", nil) 5093 5094 // WHEN 5095 err := svc.DeleteLabel(ctx, testCase.InputApplicationID, testCase.InputKey) 5096 5097 // then 5098 if testCase.ExpectedErrMessage == "" { 5099 require.NoError(t, err) 5100 } else { 5101 require.Error(t, err) 5102 assert.Contains(t, err.Error(), testCase.ExpectedErrMessage) 5103 } 5104 5105 repo.AssertExpectations(t) 5106 }) 5107 } 5108 } 5109 5110 func TestService_GetBySystemNumber(t *testing.T) { 5111 tnt := "tenant" 5112 externalTnt := "external-tnt" 5113 5114 modelApp := fixModelApplication("foo", "tenant-foo", "foo", "Lorem Ipsum") 5115 ctx := context.TODO() 5116 ctx = tenant.SaveToContext(ctx, tnt, externalTnt) 5117 testError := errors.New("Test error") 5118 systemNumber := "1" 5119 5120 testCases := []struct { 5121 Name string 5122 RepositoryFn func() *automock.ApplicationRepository 5123 InputSystemNumber string 5124 ExptectedValue *model.Application 5125 ExpectedError error 5126 }{ 5127 { 5128 Name: "Application found", 5129 RepositoryFn: func() *automock.ApplicationRepository { 5130 repo := &automock.ApplicationRepository{} 5131 repo.On("GetBySystemNumber", ctx, tnt, systemNumber).Return(modelApp, nil) 5132 return repo 5133 }, 5134 InputSystemNumber: systemNumber, 5135 ExptectedValue: modelApp, 5136 ExpectedError: nil, 5137 }, 5138 { 5139 Name: "Returns error", 5140 RepositoryFn: func() *automock.ApplicationRepository { 5141 repo := &automock.ApplicationRepository{} 5142 repo.On("GetBySystemNumber", ctx, tnt, systemNumber).Return(nil, testError) 5143 return repo 5144 }, 5145 InputSystemNumber: systemNumber, 5146 ExptectedValue: nil, 5147 ExpectedError: testError, 5148 }, 5149 } 5150 5151 for _, testCase := range testCases { 5152 t.Run(testCase.Name, func(t *testing.T) { 5153 // GIVEN 5154 appRepo := testCase.RepositoryFn() 5155 svc := application.NewService(nil, nil, appRepo, nil, nil, nil, nil, nil, nil, nil, nil, "", nil) 5156 5157 // WHEN 5158 value, err := svc.GetBySystemNumber(ctx, testCase.InputSystemNumber) 5159 5160 // THEN 5161 if testCase.ExpectedError != nil { 5162 require.Error(t, err) 5163 assert.Contains(t, err.Error(), testCase.ExpectedError.Error()) 5164 } else { 5165 require.Nil(t, err) 5166 } 5167 5168 assert.Equal(t, testCase.ExptectedValue, value) 5169 appRepo.AssertExpectations(t) 5170 }) 5171 } 5172 } 5173 5174 type testModel struct { 5175 ApplicationMatcherFn func(app *model.Application) bool 5176 Webhooks []*model.Webhook 5177 APIs []*model.APIDefinition 5178 EventAPIs []*model.EventDefinition 5179 Documents []*model.Document 5180 } 5181 5182 type MatcherFunc func(app *model.Application) bool 5183 5184 func modelFromInput(in model.ApplicationRegisterInput, tenant, applicationID string, applicationModelMatcherFn MatcherFunc) testModel { 5185 webhooksModel := make([]*model.Webhook, 0, len(in.Webhooks)) 5186 for _, item := range in.Webhooks { 5187 webhooksModel = append(webhooksModel, item.ToWebhook(uuid.New().String(), applicationID, model.ApplicationWebhookReference)) 5188 } 5189 5190 return testModel{ 5191 ApplicationMatcherFn: applicationModelMatcherFn, 5192 Webhooks: webhooksModel, 5193 } 5194 } 5195 5196 func convertToStringArray(t *testing.T, array []interface{}) []string { 5197 stringArray := make([]string, 0, len(array)) 5198 for _, value := range array { 5199 convertedValue, ok := value.(string) 5200 require.True(t, ok, "Cannot convert array of interface{} to array of string in test method") 5201 stringArray = append(stringArray, convertedValue) 5202 } 5203 return stringArray 5204 } 5205 5206 func applicationMatcher(name string, description *string) func(app *model.Application) bool { 5207 return func(app *model.Application) bool { 5208 return app.Name == name && app.Description == description 5209 } 5210 } 5211 5212 func applicationFromTemplateMatcher(name string, description *string, appTemplateID *string) func(app *model.Application) bool { 5213 return func(app *model.Application) bool { 5214 return applicationMatcher(name, description)(app) && app.ApplicationTemplateID == appTemplateID 5215 } 5216 } 5217 5218 func applicationRegisterInputWithScenarios() model.ApplicationRegisterInput { 5219 return model.ApplicationRegisterInput{ 5220 Name: "foo.bar-not", 5221 BaseURL: str.Ptr("http://test.com"), 5222 Webhooks: []*model.WebhookInput{ 5223 {URL: stringPtr("test.foo.com")}, 5224 {URL: stringPtr("test.bar.com")}, 5225 }, 5226 Labels: map[string]interface{}{ 5227 "label": "value", 5228 "applicationType": "test-app-with-ppms", 5229 "ppmsProductVersionId": "1", 5230 model.ScenariosKey: []interface{}{testScenario}, 5231 }, 5232 IntegrationSystemID: &intSysID, 5233 Bundles: []*model.BundleCreateInput{ 5234 { 5235 Name: "bndl1", 5236 APIDefinitions: []*model.APIDefinitionInput{ 5237 { 5238 Name: "foo", 5239 }, 5240 { 5241 Name: "bar", 5242 }, 5243 }, 5244 APISpecs: []*model.SpecInput{ 5245 { 5246 FetchRequest: &model.FetchRequestInput{URL: "api.foo.bar"}, 5247 }, 5248 nil, 5249 }, 5250 EventDefinitions: []*model.EventDefinitionInput{ 5251 { 5252 Name: "foo", 5253 }, 5254 { 5255 Name: "bar", 5256 }, 5257 }, 5258 EventSpecs: []*model.SpecInput{ 5259 { 5260 FetchRequest: &model.FetchRequestInput{URL: "eventapi.foo.bar"}, 5261 }, 5262 nil, 5263 }, 5264 Documents: []*model.DocumentInput{ 5265 {Title: "foo", Description: "test", FetchRequest: &model.FetchRequestInput{URL: "doc.foo.bar"}}, 5266 {Title: "bar", Description: "test"}, 5267 }, 5268 }, 5269 }, 5270 } 5271 } 5272 5273 func UnusedLabelService() *automock.LabelService { 5274 return &automock.LabelService{} 5275 } 5276 func UnusedBundleService() *automock.BundleService { 5277 return &automock.BundleService{} 5278 } 5279 func UnusedUIDService() *automock.UIDService { 5280 return &automock.UIDService{} 5281 } 5282 5283 func UnusedFormationService() *automock.FormationService { 5284 return &automock.FormationService{} 5285 } 5286 5287 func UnusedWebhookRepository() *automock.WebhookRepository { 5288 return &automock.WebhookRepository{} 5289 } 5290 5291 func UnusedIntegrationSystemRepository() *automock.IntegrationSystemRepository { 5292 return &automock.IntegrationSystemRepository{} 5293 } 5294 5295 func UnusedLabelRepository() *automock.LabelRepository { 5296 return &automock.LabelRepository{} 5297 } 5298 5299 func UnusedApplicationRepository() *automock.ApplicationRepository { 5300 return &automock.ApplicationRepository{} 5301 } 5302 5303 func UnusedLabelUpsertService() *automock.LabelService { 5304 return &automock.LabelService{} 5305 }