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  }