github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/application/converter_test.go (about) 1 package application_test 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/google/uuid" 9 "github.com/kyma-incubator/compass/components/director/internal/repo" 10 "github.com/kyma-incubator/compass/components/director/pkg/str" 11 "github.com/pkg/errors" 12 13 "github.com/stretchr/testify/require" 14 15 "github.com/kyma-incubator/compass/components/director/internal/repo/testdb" 16 17 "github.com/kyma-incubator/compass/components/director/internal/domain/application" 18 "github.com/kyma-incubator/compass/components/director/internal/domain/application/automock" 19 "github.com/kyma-incubator/compass/components/director/internal/model" 20 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func TestConverter_ToGraphQL(t *testing.T) { 25 // GIVEN 26 testCases := []struct { 27 Name string 28 Input *model.Application 29 Expected *graphql.Application 30 }{ 31 { 32 Name: "All properties given", 33 Input: fixDetailedModelApplication(t, givenID(), givenTenant(), "Foo", "Lorem ipsum"), 34 Expected: fixDetailedGQLApplication(t, givenID(), "Foo", "Lorem ipsum"), 35 }, 36 { 37 Name: "Empty", 38 Input: &model.Application{BaseEntity: &model.BaseEntity{}}, 39 Expected: &graphql.Application{ 40 Status: &graphql.ApplicationStatus{ 41 Condition: graphql.ApplicationStatusConditionInitial, 42 }, 43 BaseEntity: &graphql.BaseEntity{}, 44 }, 45 }, 46 { 47 Name: "Nil", 48 Input: nil, 49 Expected: nil, 50 }, 51 } 52 53 for _, testCase := range testCases { 54 t.Run(testCase.Name, func(t *testing.T) { 55 // WHEN 56 converter := application.NewConverter(nil, nil) 57 res := converter.ToGraphQL(testCase.Input) 58 59 // then 60 assert.Equal(t, testCase.Expected, res) 61 }) 62 } 63 } 64 65 func TestConverter_MultipleToGraphQL(t *testing.T) { 66 // GIVEN 67 input := []*model.Application{ 68 fixModelApplication("foo", givenTenant(), "Foo", "Lorem ipsum"), 69 fixModelApplication("bar", givenTenant(), "Bar", "Dolor sit amet"), 70 {BaseEntity: &model.BaseEntity{}}, 71 nil, 72 } 73 expected := []*graphql.Application{ 74 fixGQLApplication("foo", "Foo", "Lorem ipsum"), 75 fixGQLApplication("bar", "Bar", "Dolor sit amet"), 76 { 77 BaseEntity: &graphql.BaseEntity{}, 78 Status: &graphql.ApplicationStatus{ 79 Condition: graphql.ApplicationStatusConditionInitial, 80 }, 81 }, 82 } 83 84 // WHEN 85 converter := application.NewConverter(nil, nil) 86 res := converter.MultipleToGraphQL(input) 87 88 // then 89 assert.Equal(t, expected, res) 90 } 91 92 func TestConverter_CreateInputFromGraphQL(t *testing.T) { 93 allPropsInput := fixGQLApplicationRegisterInput("foo", "Lorem ipsum") 94 allPropsExpected := fixModelApplicationRegisterInput("foo", "Lorem ipsum") 95 96 webhooksErr := errors.New("wh err") 97 bndlsErr := errors.New("bndl err") 98 99 // GIVEN 100 testCases := []struct { 101 Name string 102 Input graphql.ApplicationRegisterInput 103 Expected model.ApplicationRegisterInput 104 ExpectedErr error 105 WebhookConverterFn func() *automock.WebhookConverter 106 BundleConverterFn func() *automock.BundleConverter 107 }{ 108 { 109 Name: "Succeeds when all properties are given", 110 Input: allPropsInput, 111 Expected: allPropsExpected, 112 WebhookConverterFn: func() *automock.WebhookConverter { 113 conv := &automock.WebhookConverter{} 114 conv.On("MultipleInputFromGraphQL", allPropsInput.Webhooks).Return(allPropsExpected.Webhooks, nil) 115 return conv 116 }, 117 BundleConverterFn: func() *automock.BundleConverter { 118 conv := &automock.BundleConverter{} 119 conv.On("MultipleCreateInputFromGraphQL", allPropsInput.Bundles).Return(allPropsExpected.Bundles, nil) 120 return conv 121 }, 122 }, 123 { 124 Name: "Succeeds when empty", 125 Input: graphql.ApplicationRegisterInput{}, 126 Expected: model.ApplicationRegisterInput{}, 127 WebhookConverterFn: func() *automock.WebhookConverter { 128 conv := &automock.WebhookConverter{} 129 conv.On("MultipleInputFromGraphQL", []*graphql.WebhookInput(nil)).Return(nil, nil) 130 return conv 131 }, 132 BundleConverterFn: func() *automock.BundleConverter { 133 conv := &automock.BundleConverter{} 134 conv.On("MultipleCreateInputFromGraphQL", []*graphql.BundleCreateInput(nil)).Return(nil, nil) 135 return conv 136 }, 137 }, 138 { 139 Name: "Returns error when webhook conversion fails", 140 Input: graphql.ApplicationRegisterInput{}, 141 ExpectedErr: webhooksErr, 142 143 WebhookConverterFn: func() *automock.WebhookConverter { 144 conv := &automock.WebhookConverter{} 145 conv.On("MultipleInputFromGraphQL", []*graphql.WebhookInput(nil)).Return(nil, webhooksErr) 146 return conv 147 }, 148 BundleConverterFn: func() *automock.BundleConverter { return &automock.BundleConverter{} }, 149 }, 150 { 151 Name: "Returns error when bundles conversion fails", 152 Input: graphql.ApplicationRegisterInput{}, 153 ExpectedErr: bndlsErr, 154 WebhookConverterFn: func() *automock.WebhookConverter { 155 conv := &automock.WebhookConverter{} 156 conv.On("MultipleInputFromGraphQL", []*graphql.WebhookInput(nil)).Return(nil, nil) 157 return conv 158 }, 159 BundleConverterFn: func() *automock.BundleConverter { 160 conv := &automock.BundleConverter{} 161 conv.On("MultipleCreateInputFromGraphQL", []*graphql.BundleCreateInput(nil)).Return(nil, bndlsErr) 162 return conv 163 }, 164 }, 165 } 166 167 for _, testCase := range testCases { 168 t.Run(testCase.Name, func(t *testing.T) { 169 // WHEN 170 converter := application.NewConverter( 171 testCase.WebhookConverterFn(), 172 testCase.BundleConverterFn(), 173 ) 174 res, err := converter.CreateInputFromGraphQL(context.TODO(), testCase.Input) 175 176 // then 177 if testCase.ExpectedErr != nil { 178 assert.Error(t, err) 179 assert.ErrorIs(t, err, testCase.ExpectedErr) 180 } else { 181 assert.NoError(t, err) 182 assert.Equal(t, testCase.Expected, res) 183 } 184 }) 185 } 186 } 187 188 func TestConverter_UpdateInputFromGraphQL_StatusCondition(t *testing.T) { 189 testCases := []struct { 190 Name string 191 CondtionGQL graphql.ApplicationStatusCondition 192 ConditionModel model.ApplicationStatusCondition 193 }{ 194 { 195 Name: "When status condition is FAILED", 196 CondtionGQL: graphql.ApplicationStatusConditionFailed, 197 ConditionModel: model.ApplicationStatusConditionFailed, 198 }, 199 { 200 Name: "When status condition is CONNECTED", 201 CondtionGQL: graphql.ApplicationStatusConditionConnected, 202 ConditionModel: model.ApplicationStatusConditionConnected, 203 }, 204 { 205 Name: "When status condition is INITIAL", 206 CondtionGQL: graphql.ApplicationStatusConditionInitial, 207 ConditionModel: model.ApplicationStatusConditionInitial, 208 }, 209 } 210 211 for _, testCase := range testCases { 212 t.Run(testCase.Name, func(t *testing.T) { 213 gqlApp := graphql.ApplicationUpdateInput{StatusCondition: &testCase.CondtionGQL} 214 215 converter := application.NewConverter(nil, nil) 216 modelApp := converter.UpdateInputFromGraphQL(gqlApp) 217 218 require.Equal(t, &testCase.ConditionModel, modelApp.StatusCondition) 219 }) 220 } 221 } 222 223 func TestConverter_UpdateInputFromGraphQL(t *testing.T) { 224 allPropsInput := fixGQLApplicationUpdateInput("foo", "Lorem ipsum", testURL, "baseUrl", "ns", graphql.ApplicationStatusConditionConnected) 225 allPropsExpected := fixModelApplicationUpdateInput("foo", "Lorem ipsum", testURL, "baseUrl", "ns", model.ApplicationStatusConditionConnected) 226 227 // GIVEN 228 testCases := []struct { 229 Name string 230 Input graphql.ApplicationUpdateInput 231 Expected model.ApplicationUpdateInput 232 }{ 233 { 234 Name: "All properties given", 235 Input: allPropsInput, 236 Expected: allPropsExpected, 237 }, 238 { 239 Name: "Empty", 240 Input: graphql.ApplicationUpdateInput{}, 241 Expected: model.ApplicationUpdateInput{}, 242 }, 243 } 244 245 for _, testCase := range testCases { 246 t.Run(testCase.Name, func(t *testing.T) { 247 // WHEN 248 converter := application.NewConverter(nil, nil) 249 res := converter.UpdateInputFromGraphQL(testCase.Input) 250 251 // then 252 assert.Equal(t, testCase.Expected, res) 253 }) 254 } 255 } 256 257 func TestConverter_ToEntity(t *testing.T) { 258 conv := application.NewConverter(nil, nil) 259 260 t.Run("All properties given", func(t *testing.T) { 261 // GIVEN 262 appModel := fixDetailedModelApplication(t, givenID(), givenTenant(), "app-name", "app-description") 263 264 // WHEN 265 appEntity, err := conv.ToEntity(appModel) 266 267 // THEN 268 assert.NoError(t, err) 269 assertApplicationDefinition(t, appModel, appEntity) 270 }) 271 272 t.Run("Nil", func(t *testing.T) { 273 // WHEN 274 appEntity, err := conv.ToEntity(nil) 275 276 // THEN 277 assert.NoError(t, err) 278 assert.Nil(t, appEntity) 279 }) 280 281 t.Run("Empty", func(t *testing.T) { 282 // GIVEN 283 appModel := &model.Application{} 284 285 // WHEN 286 appEntity, err := conv.ToEntity(appModel) 287 288 // THEN 289 if err != nil { 290 assert.Contains(t, err.Error(), "invalid input model") 291 } else { 292 assertApplicationDefinition(t, appModel, appEntity) 293 } 294 }) 295 } 296 297 func TestConverter_FromEntity(t *testing.T) { 298 conv := application.NewConverter(nil, nil) 299 300 t.Run("All properties given", func(t *testing.T) { 301 // GIVEN 302 appEntity := fixDetailedEntityApplication(t, givenID(), givenTenant(), "app-name", "app-description") 303 304 // WHEN 305 appModel := conv.FromEntity(appEntity) 306 307 // THEN 308 assertApplicationDefinition(t, appModel, appEntity) 309 }) 310 311 t.Run("Nil", func(t *testing.T) { 312 // WHEN 313 appModel := conv.FromEntity(nil) 314 315 // THEN 316 assert.Nil(t, appModel) 317 }) 318 319 t.Run("Empty", func(t *testing.T) { 320 // GIVEN 321 appEntity := &application.Entity{BaseEntity: &repo.BaseEntity{}} 322 323 // WHEN 324 appModel := conv.FromEntity(appEntity) 325 326 // THEN 327 assertApplicationDefinition(t, appModel, appEntity) 328 }) 329 } 330 331 func TestConverter_CreateRegisterInputJSONToGQL(t *testing.T) { 332 // GIVEN 333 conv := application.NewConverter(nil, nil) 334 335 t.Run("Successful two-way conversion", func(t *testing.T) { 336 inputGQL := fixGQLApplicationRegisterInput("name", "description") 337 inputGQL.Labels = graphql.Labels{"test": "test"} 338 339 // WHEN 340 // GQL -> JSON 341 json, err := conv.CreateRegisterInputGQLToJSON(&inputGQL) 342 require.NoError(t, err) 343 344 // JSON -> GQL 345 outputGQL, err := conv.CreateRegisterInputJSONToGQL(json) 346 require.NoError(t, err) 347 348 // THEN 349 require.Equal(t, inputGQL, outputGQL) 350 }) 351 352 t.Run("Error while JSON to GQL conversion", func(t *testing.T) { 353 // WHEN 354 expectedErr := "invalid character 'a' looking for beginning of value" 355 _, err := conv.CreateRegisterInputJSONToGQL("ad[sd") 356 357 // THEN 358 require.Error(t, err) 359 require.Contains(t, err.Error(), expectedErr) 360 }) 361 } 362 363 func TestConverter_CreateJSONInputJSONToGQL(t *testing.T) { 364 // GIVEN 365 conv := application.NewConverter(nil, nil) 366 367 t.Run("Successful two-way conversion", func(t *testing.T) { 368 inputGQL := fixGQLApplicationJSONInput("name", "description") 369 inputGQL.Labels = graphql.Labels{"test": "test"} 370 371 // WHEN 372 // GQL -> JSON 373 json, err := conv.CreateJSONInputGQLToJSON(&inputGQL) 374 require.NoError(t, err) 375 376 // JSON -> GQL 377 outputGQL, err := conv.CreateJSONInputJSONToGQL(json) 378 require.NoError(t, err) 379 380 // THEN 381 require.Equal(t, inputGQL, outputGQL) 382 }) 383 384 t.Run("Error while JSON to GQL conversion", func(t *testing.T) { 385 // WHEN 386 expectedErr := "invalid character 'a' looking for beginning of value" 387 _, err := conv.CreateJSONInputJSONToGQL("ad[sd") 388 389 // THEN 390 require.Error(t, err) 391 require.Contains(t, err.Error(), expectedErr) 392 }) 393 } 394 395 func TestConverter_CreateInputJSONToModelL(t *testing.T) { 396 t.Run("Successful conversion", func(t *testing.T) { 397 // GIVEN 398 cond := model.ApplicationStatusConditionInitial 399 appInput := model.ApplicationRegisterInput{ 400 Name: "test", 401 Description: str.Ptr("test description"), 402 StatusCondition: &cond, 403 Labels: map[string]interface{}{ 404 "key": "value", 405 }, 406 } 407 appInputJSON := fmt.Sprintf(`{"name": "%s","description": "%s","statusCondition": "%s","labels": {"key": "value"}}`, 408 appInput.Name, *appInput.Description, string(cond)) 409 410 conv := application.NewConverter(nil, nil) 411 412 // WHEN 413 outputModel, err := conv.CreateInputJSONToModel(context.TODO(), appInputJSON) 414 415 // THEN 416 require.NoError(t, err) 417 require.Equal(t, appInput, outputModel) 418 }) 419 t.Run("Error while JSON to GQL conversion", func(t *testing.T) { 420 // GIVEN 421 conv := application.NewConverter(nil, nil) 422 423 // WHEN 424 _, err := conv.CreateInputJSONToModel(context.TODO(), "test") 425 426 // THEN 427 require.Error(t, err) 428 }) 429 } 430 431 func TestConverter_ConvertToModel(t *testing.T) { 432 conv := application.NewConverter(nil, nil) 433 434 t.Run("Successful full model", func(t *testing.T) { 435 tenantID := uuid.New().String() 436 appGraphql := fixGQLApplication(uuid.New().String(), "app", "desc") 437 438 // WHEN 439 appModel := conv.GraphQLToModel(appGraphql, tenantID) 440 outputGraphql := conv.ToGraphQL(appModel) 441 442 // THEN 443 assert.Equal(t, appGraphql, outputGraphql) 444 }) 445 446 t.Run("Success empty model", func(t *testing.T) { 447 // GIVEN 448 appGraphql := &graphql.Application{BaseEntity: &graphql.BaseEntity{}} 449 450 // WHEN 451 appModel := conv.GraphQLToModel(appGraphql, uuid.New().String()) 452 outputGraphql := conv.ToGraphQL(appModel) 453 454 // THEN 455 appGraphql.Status = &graphql.ApplicationStatus{Condition: graphql.ApplicationStatusConditionInitial} 456 assert.Equal(t, appGraphql, outputGraphql) 457 }) 458 459 t.Run("Nil model", func(t *testing.T) { 460 // WHEN 461 output := conv.GraphQLToModel(nil, uuid.New().String()) 462 // THEN 463 require.Nil(t, output) 464 }) 465 } 466 467 func assertApplicationDefinition(t *testing.T, appModel *model.Application, entity *application.Entity) { 468 assert.Equal(t, appModel.ID, entity.ID) 469 assert.Equal(t, appModel.Name, entity.Name) 470 471 if appModel.Status != nil { 472 assert.Equal(t, appModel.Status.Condition, model.ApplicationStatusCondition(entity.StatusCondition)) 473 assert.Equal(t, appModel.Status.Timestamp, entity.StatusTimestamp) 474 } else { 475 assert.Equal(t, string(model.ApplicationStatusConditionInitial), entity.StatusCondition) 476 } 477 478 testdb.AssertSQLNullStringEqualTo(t, entity.Description, appModel.Description) 479 testdb.AssertSQLNullStringEqualTo(t, entity.HealthCheckURL, appModel.HealthCheckURL) 480 testdb.AssertSQLNullStringEqualTo(t, entity.ProviderName, appModel.ProviderName) 481 } 482 483 func givenID() string { 484 return "bd0646fa-3c30-4255-84f8-182f57742aa1" 485 } 486 487 func givenTenant() string { 488 return "8f237125-50be-4bb4-96ce-389e2b931f46" 489 } 490 491 func givenTenantAsUUID() uuid.UUID { 492 parse, err := uuid.Parse("8f237125-50be-4bb4-96ce-389e2b931f46") 493 if err != nil { 494 panic(err) 495 } 496 497 return parse 498 }