github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/document/resolver_test.go (about) 1 package document_test 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/kyma-incubator/compass/components/director/pkg/resource" 10 11 dataloader "github.com/kyma-incubator/compass/components/director/internal/dataloaders" 12 13 "github.com/kyma-incubator/compass/components/director/internal/model" 14 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 15 "github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest" 16 17 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 18 "github.com/stretchr/testify/mock" 19 20 "github.com/stretchr/testify/require" 21 22 "github.com/kyma-incubator/compass/components/director/internal/domain/document" 23 "github.com/kyma-incubator/compass/components/director/internal/domain/document/automock" 24 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 25 persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock" 26 "github.com/stretchr/testify/assert" 27 ) 28 29 var contextParam = mock.MatchedBy(func(ctx context.Context) bool { 30 persistenceOp, err := persistence.FromCtx(ctx) 31 return err == nil && persistenceOp != nil 32 }) 33 34 func TestResolver_AddDocumentToBundle(t *testing.T) { 35 // GIVEN 36 testErr := errors.New("Test error") 37 38 bundleID := "bar" 39 id := "bar" 40 modelBundle := fixModelBundle(bundleID) 41 modelDocument := fixModelDocumentForApp(id, bundleID) 42 gqlDocument := fixGQLDocument(id, bundleID) 43 gqlInput := fixGQLDocumentInput(id) 44 modelInput := fixModelDocumentInput(id) 45 46 testCases := []struct { 47 Name string 48 PersistenceFn func() *persistenceautomock.PersistenceTx 49 TransactionerFn func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner 50 ServiceFn func() *automock.DocumentService 51 BndlServiceFn func() *automock.BundleService 52 ConverterFn func() *automock.DocumentConverter 53 ExpectedDocument *graphql.Document 54 ExpectedErr error 55 }{ 56 { 57 Name: "Success", 58 PersistenceFn: func() *persistenceautomock.PersistenceTx { 59 persistTx := &persistenceautomock.PersistenceTx{} 60 persistTx.On("Commit").Return(nil).Once() 61 return persistTx 62 }, 63 TransactionerFn: txtest.TransactionerThatSucceeds, 64 ServiceFn: func() *automock.DocumentService { 65 svc := &automock.DocumentService{} 66 svc.On("CreateInBundle", contextParam, resource.Application, appID, bundleID, *modelInput).Return(id, nil).Once() 67 svc.On("Get", contextParam, id).Return(modelDocument, nil).Once() 68 return svc 69 }, 70 BndlServiceFn: func() *automock.BundleService { 71 appSvc := &automock.BundleService{} 72 appSvc.On("Get", contextParam, bundleID).Return(modelBundle, nil) 73 return appSvc 74 }, 75 ConverterFn: func() *automock.DocumentConverter { 76 conv := &automock.DocumentConverter{} 77 conv.On("InputFromGraphQL", gqlInput).Return(modelInput, nil).Once() 78 conv.On("ToGraphQL", modelDocument).Return(gqlDocument).Once() 79 return conv 80 }, 81 ExpectedDocument: gqlDocument, 82 ExpectedErr: nil, 83 }, 84 { 85 Name: "Returns error when bundle does not exits", 86 PersistenceFn: func() *persistenceautomock.PersistenceTx { 87 persistTx := &persistenceautomock.PersistenceTx{} 88 return persistTx 89 }, 90 TransactionerFn: txtest.TransactionerThatDoesARollback, 91 ServiceFn: func() *automock.DocumentService { 92 svc := &automock.DocumentService{} 93 return svc 94 }, 95 BndlServiceFn: func() *automock.BundleService { 96 appSvc := &automock.BundleService{} 97 appSvc.On("Get", contextParam, bundleID).Return(nil, apperrors.NewNotFoundError(resource.Bundle, bundleID)) 98 return appSvc 99 }, 100 ConverterFn: func() *automock.DocumentConverter { 101 conv := &automock.DocumentConverter{} 102 conv.On("InputFromGraphQL", gqlInput).Return(modelInput, nil).Once() 103 return conv 104 }, 105 106 ExpectedDocument: nil, 107 ExpectedErr: errors.New("cannot add Document to not existing Bundle"), 108 }, 109 { 110 Name: "Returns error when application existence check failed", 111 PersistenceFn: func() *persistenceautomock.PersistenceTx { 112 persistTx := &persistenceautomock.PersistenceTx{} 113 return persistTx 114 }, 115 TransactionerFn: txtest.TransactionerThatDoesARollback, 116 ServiceFn: func() *automock.DocumentService { 117 svc := &automock.DocumentService{} 118 return svc 119 }, 120 BndlServiceFn: func() *automock.BundleService { 121 appSvc := &automock.BundleService{} 122 appSvc.On("Get", contextParam, bundleID).Return(modelBundle, testErr) 123 return appSvc 124 }, 125 ConverterFn: func() *automock.DocumentConverter { 126 conv := &automock.DocumentConverter{} 127 conv.On("InputFromGraphQL", gqlInput).Return(modelInput, nil).Once() 128 return conv 129 }, 130 131 ExpectedDocument: nil, 132 ExpectedErr: testErr, 133 }, 134 { 135 Name: "Returns error when document creation failed", 136 PersistenceFn: func() *persistenceautomock.PersistenceTx { 137 persistTx := &persistenceautomock.PersistenceTx{} 138 return persistTx 139 }, 140 TransactionerFn: txtest.TransactionerThatDoesARollback, 141 ServiceFn: func() *automock.DocumentService { 142 svc := &automock.DocumentService{} 143 svc.On("CreateInBundle", contextParam, resource.Application, appID, bundleID, *modelInput).Return("", testErr).Once() 144 return svc 145 }, 146 BndlServiceFn: func() *automock.BundleService { 147 appSvc := &automock.BundleService{} 148 appSvc.On("Get", contextParam, bundleID).Return(modelBundle, nil) 149 return appSvc 150 }, 151 ConverterFn: func() *automock.DocumentConverter { 152 conv := &automock.DocumentConverter{} 153 conv.On("InputFromGraphQL", gqlInput).Return(modelInput, nil).Once() 154 return conv 155 }, 156 ExpectedDocument: nil, 157 ExpectedErr: testErr, 158 }, 159 { 160 Name: "Returns error when document retrieval failed", 161 PersistenceFn: func() *persistenceautomock.PersistenceTx { 162 persistTx := &persistenceautomock.PersistenceTx{} 163 return persistTx 164 }, 165 TransactionerFn: txtest.TransactionerThatSucceeds, 166 ServiceFn: func() *automock.DocumentService { 167 svc := &automock.DocumentService{} 168 svc.On("CreateInBundle", contextParam, resource.Application, appID, bundleID, *modelInput).Return(id, nil).Once() 169 svc.On("Get", contextParam, id).Return(nil, testErr).Once() 170 return svc 171 }, 172 BndlServiceFn: func() *automock.BundleService { 173 appSvc := &automock.BundleService{} 174 appSvc.On("Get", contextParam, bundleID).Return(modelBundle, nil) 175 return appSvc 176 }, 177 ConverterFn: func() *automock.DocumentConverter { 178 conv := &automock.DocumentConverter{} 179 conv.On("InputFromGraphQL", gqlInput).Return(modelInput, nil).Once() 180 return conv 181 }, 182 ExpectedDocument: nil, 183 ExpectedErr: testErr, 184 }, 185 } 186 187 for _, testCase := range testCases { 188 t.Run(testCase.Name, func(t *testing.T) { 189 persistTx := testCase.PersistenceFn() 190 transact := testCase.TransactionerFn(persistTx) 191 svc := testCase.ServiceFn() 192 bndlSvc := testCase.BndlServiceFn() 193 converter := testCase.ConverterFn() 194 195 resolver := document.NewResolver(transact, svc, nil, bndlSvc, nil) 196 resolver.SetConverter(converter) 197 198 // WHEN 199 result, err := resolver.AddDocumentToBundle(context.TODO(), bundleID, *gqlInput) 200 201 // then 202 assert.Equal(t, testCase.ExpectedDocument, result) 203 if testCase.ExpectedErr == nil { 204 require.NoError(t, err) 205 } else { 206 require.Error(t, err) 207 assert.Contains(t, err.Error(), testCase.ExpectedErr.Error()) 208 } 209 210 persistTx.AssertExpectations(t) 211 transact.AssertExpectations(t) 212 svc.AssertExpectations(t) 213 bndlSvc.AssertExpectations(t) 214 converter.AssertExpectations(t) 215 }) 216 } 217 } 218 219 func TestResolver_DeleteDocument(t *testing.T) { 220 // GIVEN 221 testErr := errors.New("Test error") 222 223 id := "bar" 224 bundleID := "bar" 225 modelDocument := fixModelDocumentForApp(id, bundleID) 226 gqlDocument := fixGQLDocument(id, bundleID) 227 228 testCases := []struct { 229 Name string 230 PersistenceFn func() *persistenceautomock.PersistenceTx 231 TransactionerFn func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner 232 ServiceFn func() *automock.DocumentService 233 ConverterFn func() *automock.DocumentConverter 234 ExpectedDocument *graphql.Document 235 ExpectedErr error 236 }{ 237 { 238 Name: "Success", 239 PersistenceFn: func() *persistenceautomock.PersistenceTx { 240 persistTx := &persistenceautomock.PersistenceTx{} 241 persistTx.On("Commit").Return(nil).Once() 242 return persistTx 243 }, 244 TransactionerFn: txtest.TransactionerThatSucceeds, 245 ServiceFn: func() *automock.DocumentService { 246 svc := &automock.DocumentService{} 247 svc.On("Get", contextParam, id).Return(modelDocument, nil).Once() 248 svc.On("Delete", contextParam, id).Return(nil).Once() 249 return svc 250 }, 251 ConverterFn: func() *automock.DocumentConverter { 252 conv := &automock.DocumentConverter{} 253 conv.On("ToGraphQL", modelDocument).Return(gqlDocument).Once() 254 return conv 255 }, 256 ExpectedDocument: gqlDocument, 257 ExpectedErr: nil, 258 }, 259 { 260 Name: "Returns error when document retrieval failed", 261 PersistenceFn: func() *persistenceautomock.PersistenceTx { 262 persistTx := &persistenceautomock.PersistenceTx{} 263 return persistTx 264 }, 265 TransactionerFn: txtest.TransactionerThatSucceeds, 266 ServiceFn: func() *automock.DocumentService { 267 svc := &automock.DocumentService{} 268 svc.On("Get", contextParam, id).Return(nil, testErr).Once() 269 return svc 270 }, 271 ConverterFn: func() *automock.DocumentConverter { 272 conv := &automock.DocumentConverter{} 273 return conv 274 }, 275 ExpectedDocument: nil, 276 ExpectedErr: testErr, 277 }, 278 { 279 Name: "Returns error when document deletion failed", 280 PersistenceFn: func() *persistenceautomock.PersistenceTx { 281 persistTx := &persistenceautomock.PersistenceTx{} 282 return persistTx 283 }, 284 TransactionerFn: txtest.TransactionerThatSucceeds, 285 ServiceFn: func() *automock.DocumentService { 286 svc := &automock.DocumentService{} 287 svc.On("Get", contextParam, id).Return(modelDocument, nil).Once() 288 svc.On("Delete", contextParam, id).Return(testErr).Once() 289 return svc 290 }, 291 ConverterFn: func() *automock.DocumentConverter { 292 conv := &automock.DocumentConverter{} 293 conv.On("ToGraphQL", modelDocument).Return(gqlDocument).Once() 294 return conv 295 }, 296 ExpectedDocument: nil, 297 ExpectedErr: testErr, 298 }, 299 } 300 301 for _, testCase := range testCases { 302 t.Run(testCase.Name, func(t *testing.T) { 303 persistTx := testCase.PersistenceFn() 304 transact := testCase.TransactionerFn(persistTx) 305 svc := testCase.ServiceFn() 306 converter := testCase.ConverterFn() 307 308 resolver := document.NewResolver(transact, svc, nil, nil, nil) 309 resolver.SetConverter(converter) 310 311 // WHEN 312 result, err := resolver.DeleteDocument(context.TODO(), id) 313 314 // then 315 assert.Equal(t, testCase.ExpectedDocument, result) 316 assert.Equal(t, testCase.ExpectedErr, err) 317 318 persistTx.AssertExpectations(t) 319 transact.AssertExpectations(t) 320 svc.AssertExpectations(t) 321 converter.AssertExpectations(t) 322 }) 323 } 324 } 325 326 func TestResolver_FetchRequest(t *testing.T) { 327 // GIVEN 328 testErr := errors.New("test error") 329 330 firstDocID := "docID" 331 secondDocID := "docID2" 332 docIDs := []string{firstDocID, secondDocID} 333 firstFRID := "frID" 334 secondFRID := "frID2" 335 frURL := "foo.bar" 336 timestamp := time.Now() 337 338 frFirstDoc := fixModelFetchRequest(firstFRID, frURL, timestamp) 339 frSecondDoc := fixModelFetchRequest(secondFRID, frURL, timestamp) 340 fetchRequests := []*model.FetchRequest{frFirstDoc, frSecondDoc} 341 342 gqlFRFirstDoc := fixGQLFetchRequest(frURL, timestamp) 343 gqlFRSecondDoc := fixGQLFetchRequest(frURL, timestamp) 344 gqlFetchRequests := []*graphql.FetchRequest{gqlFRFirstDoc, gqlFRSecondDoc} 345 346 txGen := txtest.NewTransactionContextGenerator(testErr) 347 348 testCases := []struct { 349 Name string 350 TransactionerFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) 351 ServiceFn func() *automock.DocumentService 352 ConverterFn func() *automock.FetchRequestConverter 353 ExpectedResult []*graphql.FetchRequest 354 ExpectedErr []error 355 }{ 356 { 357 Name: "Success", 358 TransactionerFn: txGen.ThatSucceeds, 359 ServiceFn: func() *automock.DocumentService { 360 svc := &automock.DocumentService{} 361 svc.On("ListFetchRequests", txtest.CtxWithDBMatcher(), docIDs).Return(fetchRequests, nil).Once() 362 return svc 363 }, 364 ConverterFn: func() *automock.FetchRequestConverter { 365 conv := &automock.FetchRequestConverter{} 366 conv.On("ToGraphQL", frFirstDoc).Return(gqlFRFirstDoc, nil).Once() 367 conv.On("ToGraphQL", frSecondDoc).Return(gqlFRSecondDoc, nil).Once() 368 return conv 369 }, 370 ExpectedResult: gqlFetchRequests, 371 ExpectedErr: nil, 372 }, 373 { 374 Name: "Returns error when starting transaction failed", 375 TransactionerFn: txGen.ThatFailsOnBegin, 376 ServiceFn: func() *automock.DocumentService { 377 svc := &automock.DocumentService{} 378 return svc 379 }, 380 ConverterFn: func() *automock.FetchRequestConverter { 381 conv := &automock.FetchRequestConverter{} 382 return conv 383 }, 384 ExpectedResult: nil, 385 ExpectedErr: []error{testErr}, 386 }, 387 { 388 Name: "FetchRequest doesn't exist", 389 TransactionerFn: txGen.ThatDoesntExpectCommit, 390 ServiceFn: func() *automock.DocumentService { 391 svc := &automock.DocumentService{} 392 svc.On("ListFetchRequests", txtest.CtxWithDBMatcher(), docIDs).Return(nil, nil).Once() 393 return svc 394 }, 395 ConverterFn: func() *automock.FetchRequestConverter { 396 conv := &automock.FetchRequestConverter{} 397 return conv 398 }, 399 ExpectedResult: nil, 400 ExpectedErr: nil, 401 }, 402 { 403 Name: "Error when listing Document FetchRequests", 404 TransactionerFn: txGen.ThatDoesntExpectCommit, 405 ServiceFn: func() *automock.DocumentService { 406 svc := &automock.DocumentService{} 407 svc.On("ListFetchRequests", txtest.CtxWithDBMatcher(), docIDs).Return(nil, testErr).Once() 408 return svc 409 }, 410 ConverterFn: func() *automock.FetchRequestConverter { 411 conv := &automock.FetchRequestConverter{} 412 return conv 413 }, 414 ExpectedResult: nil, 415 ExpectedErr: []error{testErr}, 416 }, 417 { 418 Name: "Error when converting FetchRequest to graphql", 419 TransactionerFn: txGen.ThatDoesntExpectCommit, 420 ServiceFn: func() *automock.DocumentService { 421 svc := &automock.DocumentService{} 422 svc.On("ListFetchRequests", txtest.CtxWithDBMatcher(), docIDs).Return(fetchRequests, nil).Once() 423 return svc 424 }, 425 ConverterFn: func() *automock.FetchRequestConverter { 426 conv := &automock.FetchRequestConverter{} 427 conv.On("ToGraphQL", frFirstDoc).Return(nil, testErr).Once() 428 return conv 429 }, 430 ExpectedResult: nil, 431 ExpectedErr: []error{testErr}, 432 }, 433 { 434 Name: "Returns error when commit transaction fails", 435 TransactionerFn: txGen.ThatFailsOnCommit, 436 ServiceFn: func() *automock.DocumentService { 437 svc := &automock.DocumentService{} 438 svc.On("ListFetchRequests", txtest.CtxWithDBMatcher(), docIDs).Return(fetchRequests, nil).Once() 439 return svc 440 }, 441 ConverterFn: func() *automock.FetchRequestConverter { 442 conv := &automock.FetchRequestConverter{} 443 conv.On("ToGraphQL", frFirstDoc).Return(gqlFRFirstDoc, nil).Once() 444 conv.On("ToGraphQL", frSecondDoc).Return(gqlFRSecondDoc, nil).Once() 445 return conv 446 }, 447 ExpectedResult: nil, 448 ExpectedErr: []error{testErr}, 449 }, 450 } 451 452 for _, testCase := range testCases { 453 t.Run(testCase.Name, func(t *testing.T) { 454 persist, transact := testCase.TransactionerFn() 455 svc := testCase.ServiceFn() 456 converter := testCase.ConverterFn() 457 458 firstFRParams := dataloader.ParamFetchRequestDocument{ID: firstDocID, Ctx: context.TODO()} 459 secondFRParams := dataloader.ParamFetchRequestDocument{ID: secondDocID, Ctx: context.TODO()} 460 keys := []dataloader.ParamFetchRequestDocument{firstFRParams, secondFRParams} 461 resolver := document.NewResolver(transact, svc, nil, nil, converter) 462 463 // WHEN 464 result, err := resolver.FetchRequestDocumentDataLoader(keys) 465 466 // then 467 assert.Equal(t, testCase.ExpectedResult, result) 468 assert.Equal(t, testCase.ExpectedErr, err) 469 470 persist.AssertExpectations(t) 471 transact.AssertExpectations(t) 472 svc.AssertExpectations(t) 473 converter.AssertExpectations(t) 474 }) 475 } 476 t.Run("Returns error when there are no Docs", func(t *testing.T) { 477 resolver := document.NewResolver(nil, nil, nil, nil, nil) 478 // WHEN 479 _, err := resolver.FetchRequestDocumentDataLoader([]dataloader.ParamFetchRequestDocument{}) 480 // THEN 481 require.Error(t, err[0]) 482 assert.EqualError(t, err[0], apperrors.NewInternalError("No Documents found").Error()) 483 }) 484 485 t.Run("Returns error when Document ID is empty", func(t *testing.T) { 486 params := dataloader.ParamFetchRequestDocument{ID: "", Ctx: context.TODO()} 487 keys := []dataloader.ParamFetchRequestDocument{params} 488 489 resolver := document.NewResolver(nil, nil, nil, nil, nil) 490 // WHEN 491 _, err := resolver.FetchRequestDocumentDataLoader(keys) 492 // THEN 493 require.Error(t, err[0]) 494 assert.EqualError(t, err[0], apperrors.NewInternalError("Cannot fetch FetchRequest. Document ID is empty").Error()) 495 }) 496 }