github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/webhook/resolver_test.go (about)

     1  package webhook_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/model"
     9  
    10  	"github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest"
    11  
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"testing"
    15  
    16  	"github.com/kyma-incubator/compass/components/director/internal/domain/webhook"
    17  	"github.com/kyma-incubator/compass/components/director/internal/domain/webhook/automock"
    18  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    19  	persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  )
    23  
    24  func TestResolver_AddWebhook(t *testing.T) {
    25  	// GIVEN
    26  	testErr := errors.New("Test error")
    27  
    28  	givenAppID := "foo"
    29  	givenAppTemplateID := "test_app_template"
    30  	givenRuntimeID := "test_runtime"
    31  	givenFormationTemplateID := "ftID"
    32  	id := "bar"
    33  	gqlWebhookInput := fixGQLWebhookInput("foo")
    34  	modelWebhookInput := fixModelWebhookInput("foo")
    35  
    36  	gqlWebhook := fixApplicationGQLWebhook(id, "", "")
    37  	modelWebhook := fixApplicationModelWebhook(id, givenAppID, givenTenant(), "foo", time.Time{})
    38  
    39  	testCases := []struct {
    40  		Name                       string
    41  		PersistenceFn              func() *persistenceautomock.PersistenceTx
    42  		TransactionerFn            func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner
    43  		ServiceFn                  func() *automock.WebhookService
    44  		AppServiceFn               func() *automock.ApplicationService
    45  		AppTemplateServiceFn       func() *automock.ApplicationTemplateService
    46  		RuntimeServiceFn           func() *automock.RuntimeService
    47  		FormationTemplateServiceFn func() *automock.FormationTemplateService
    48  		ConverterFn                func() *automock.WebhookConverter
    49  		ExpectedWebhook            *graphql.Webhook
    50  		ExpectedErr                error
    51  	}{
    52  		{
    53  			Name:            "Success",
    54  			PersistenceFn:   txtest.PersistenceContextThatExpectsCommit,
    55  			TransactionerFn: txtest.TransactionerThatSucceeds,
    56  			ServiceFn: func() *automock.WebhookService {
    57  				svc := &automock.WebhookService{}
    58  				svc.On("Create", txtest.CtxWithDBMatcher(), givenAppID, *modelWebhookInput, model.ApplicationWebhookReference).Return(id, nil).Once()
    59  				svc.On("Get", txtest.CtxWithDBMatcher(), id, model.ApplicationWebhookReference).Return(modelWebhook, nil).Once()
    60  				return svc
    61  			},
    62  			AppServiceFn: func() *automock.ApplicationService {
    63  				appSvc := &automock.ApplicationService{}
    64  				appSvc.On("Exist", txtest.CtxWithDBMatcher(), givenAppID).Return(true, nil).Once()
    65  				return appSvc
    66  			},
    67  			ConverterFn: func() *automock.WebhookConverter {
    68  				conv := &automock.WebhookConverter{}
    69  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
    70  				conv.On("ToGraphQL", modelWebhook).Return(gqlWebhook, nil).Once()
    71  				return conv
    72  			},
    73  			ExpectedWebhook: gqlWebhook,
    74  			ExpectedErr:     nil,
    75  		},
    76  		{
    77  			Name:          "Returns error on starting transaction",
    78  			PersistenceFn: txtest.PersistenceContextThatDoesntExpectCommit,
    79  			TransactionerFn: func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner {
    80  				transact := &persistenceautomock.Transactioner{}
    81  				transact.On("Begin").Return(persistTx, givenError()).Once()
    82  				return transact
    83  			},
    84  			ServiceFn: func() *automock.WebhookService {
    85  				return &automock.WebhookService{}
    86  			},
    87  			AppServiceFn: func() *automock.ApplicationService {
    88  				return &automock.ApplicationService{}
    89  			},
    90  			ConverterFn: func() *automock.WebhookConverter {
    91  				return &automock.WebhookConverter{}
    92  			},
    93  			ExpectedErr: givenError(),
    94  		},
    95  		{
    96  			Name:            "Returns error on webhook conversion",
    97  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
    98  			TransactionerFn: txtest.TransactionerThatDoesARollback,
    99  			ServiceFn: func() *automock.WebhookService {
   100  				return &automock.WebhookService{}
   101  			},
   102  			AppServiceFn: func() *automock.ApplicationService {
   103  				return &automock.ApplicationService{}
   104  			},
   105  			ConverterFn: func() *automock.WebhookConverter {
   106  				converter := &automock.WebhookConverter{}
   107  				converter.Mock.On("InputFromGraphQL", gqlWebhookInput).Return(nil, testErr)
   108  				return converter
   109  			},
   110  			ExpectedErr: errors.New("while converting the WebhookInput: Test error"),
   111  		},
   112  		{
   113  			Name: "Returns error on committing transaction",
   114  			PersistenceFn: func() *persistenceautomock.PersistenceTx {
   115  				persistTx := &persistenceautomock.PersistenceTx{}
   116  				persistTx.On("Commit").Return(givenError()).Once()
   117  				return persistTx
   118  			},
   119  			TransactionerFn: txtest.TransactionerThatSucceeds,
   120  			ServiceFn: func() *automock.WebhookService {
   121  				svc := &automock.WebhookService{}
   122  				svc.On("Create", txtest.CtxWithDBMatcher(), givenAppID, *modelWebhookInput, model.ApplicationWebhookReference).Return(id, nil).Once()
   123  				svc.On("Get", txtest.CtxWithDBMatcher(), id, model.ApplicationWebhookReference).Return(modelWebhook, nil).Once()
   124  				return svc
   125  			},
   126  			AppServiceFn: func() *automock.ApplicationService {
   127  				appSvc := &automock.ApplicationService{}
   128  				appSvc.On("Exist", txtest.CtxWithDBMatcher(), givenAppID).Return(true, nil).Once()
   129  				return appSvc
   130  			},
   131  			ConverterFn: func() *automock.WebhookConverter {
   132  				conv := &automock.WebhookConverter{}
   133  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   134  				return conv
   135  			},
   136  			ExpectedErr: givenError(),
   137  		},
   138  		{
   139  			Name:            "Returns error when application does not exist",
   140  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   141  			TransactionerFn: txtest.TransactionerThatSucceeds,
   142  			ServiceFn: func() *automock.WebhookService {
   143  				svc := &automock.WebhookService{}
   144  				return svc
   145  			},
   146  			AppServiceFn: func() *automock.ApplicationService {
   147  				appSvc := &automock.ApplicationService{}
   148  				appSvc.On("Exist", txtest.CtxWithDBMatcher(), givenAppID).Return(false, nil)
   149  				return appSvc
   150  			},
   151  			ConverterFn: func() *automock.WebhookConverter {
   152  				conv := &automock.WebhookConverter{}
   153  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   154  				return conv
   155  			},
   156  			ExpectedWebhook: nil,
   157  			ExpectedErr:     errors.New("cannot add ApplicationWebhook due to not existing reference entity"),
   158  		},
   159  		{
   160  			Name:            "Returns error when application template does not exist",
   161  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   162  			TransactionerFn: txtest.TransactionerThatSucceeds,
   163  			ServiceFn: func() *automock.WebhookService {
   164  				svc := &automock.WebhookService{}
   165  				return svc
   166  			},
   167  			AppTemplateServiceFn: func() *automock.ApplicationTemplateService {
   168  				appTemplateSvc := &automock.ApplicationTemplateService{}
   169  				appTemplateSvc.On("Exists", txtest.CtxWithDBMatcher(), givenAppTemplateID).Return(false, nil)
   170  				return appTemplateSvc
   171  			},
   172  			ConverterFn: func() *automock.WebhookConverter {
   173  				conv := &automock.WebhookConverter{}
   174  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   175  				return conv
   176  			},
   177  			ExpectedWebhook: nil,
   178  			ExpectedErr:     errors.New("cannot add ApplicationTemplateWebhook due to not existing reference entity"),
   179  		},
   180  		{
   181  			Name:            "Returns error when runtime does not exist",
   182  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   183  			TransactionerFn: txtest.TransactionerThatSucceeds,
   184  			ServiceFn: func() *automock.WebhookService {
   185  				svc := &automock.WebhookService{}
   186  				return svc
   187  			},
   188  			RuntimeServiceFn: func() *automock.RuntimeService {
   189  				runtimeSvc := &automock.RuntimeService{}
   190  				runtimeSvc.On("Exist", txtest.CtxWithDBMatcher(), givenRuntimeID).Return(false, nil)
   191  				return runtimeSvc
   192  			},
   193  			ConverterFn: func() *automock.WebhookConverter {
   194  				conv := &automock.WebhookConverter{}
   195  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   196  				return conv
   197  			},
   198  			ExpectedWebhook: nil,
   199  			ExpectedErr:     errors.New("cannot add RuntimeWebhook due to not existing reference entity"),
   200  		},
   201  		{
   202  			Name:            "Returns error when formation template does not exist",
   203  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   204  			TransactionerFn: txtest.TransactionerThatSucceeds,
   205  			ServiceFn: func() *automock.WebhookService {
   206  				svc := &automock.WebhookService{}
   207  				return svc
   208  			},
   209  			FormationTemplateServiceFn: func() *automock.FormationTemplateService {
   210  				ftSvc := &automock.FormationTemplateService{}
   211  				ftSvc.On("Exist", txtest.CtxWithDBMatcher(), givenFormationTemplateID).Return(false, nil)
   212  				return ftSvc
   213  			},
   214  			ConverterFn: func() *automock.WebhookConverter {
   215  				conv := &automock.WebhookConverter{}
   216  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   217  				return conv
   218  			},
   219  			ExpectedWebhook: nil,
   220  			ExpectedErr:     errors.New("cannot add FormationTemplateWebhook due to not existing reference entity"),
   221  		},
   222  		{
   223  			Name:            "Returns error when application existence check failed",
   224  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   225  			TransactionerFn: txtest.TransactionerThatSucceeds,
   226  			ServiceFn: func() *automock.WebhookService {
   227  				svc := &automock.WebhookService{}
   228  				return svc
   229  			},
   230  			AppServiceFn: func() *automock.ApplicationService {
   231  				appSvc := &automock.ApplicationService{}
   232  				appSvc.On("Exist", txtest.CtxWithDBMatcher(), givenAppID).Return(false, testErr).Once()
   233  				return appSvc
   234  			},
   235  			ConverterFn: func() *automock.WebhookConverter {
   236  				conv := &automock.WebhookConverter{}
   237  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   238  				return conv
   239  			},
   240  			ExpectedWebhook: nil,
   241  			ExpectedErr:     testErr,
   242  		},
   243  		{
   244  			Name:            "Returns error when webhook creation failed",
   245  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   246  			TransactionerFn: txtest.TransactionerThatSucceeds,
   247  			ServiceFn: func() *automock.WebhookService {
   248  				svc := &automock.WebhookService{}
   249  				svc.On("Create", txtest.CtxWithDBMatcher(), givenAppID, *modelWebhookInput, model.ApplicationWebhookReference).Return("", testErr).Once()
   250  				return svc
   251  			},
   252  			AppServiceFn: func() *automock.ApplicationService {
   253  				appSvc := &automock.ApplicationService{}
   254  				appSvc.On("Exist", txtest.CtxWithDBMatcher(), givenAppID).Return(true, nil).Once()
   255  				return appSvc
   256  			},
   257  			ConverterFn: func() *automock.WebhookConverter {
   258  				conv := &automock.WebhookConverter{}
   259  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   260  				return conv
   261  			},
   262  			ExpectedWebhook: nil,
   263  			ExpectedErr:     testErr,
   264  		},
   265  		{
   266  			Name:            "Returns error when webhook retrieval failed",
   267  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   268  			TransactionerFn: txtest.TransactionerThatSucceeds,
   269  			ServiceFn: func() *automock.WebhookService {
   270  				svc := &automock.WebhookService{}
   271  				svc.On("Create", txtest.CtxWithDBMatcher(), givenAppID, *modelWebhookInput, model.ApplicationWebhookReference).Return(id, nil).Once()
   272  				svc.On("Get", txtest.CtxWithDBMatcher(), id, model.ApplicationWebhookReference).Return(nil, testErr).Once()
   273  				return svc
   274  			},
   275  			AppServiceFn: func() *automock.ApplicationService {
   276  				appSvc := &automock.ApplicationService{}
   277  				appSvc.On("Exist", txtest.CtxWithDBMatcher(), givenAppID).Return(true, nil).Once()
   278  				return appSvc
   279  			},
   280  			ConverterFn: func() *automock.WebhookConverter {
   281  				conv := &automock.WebhookConverter{}
   282  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   283  				return conv
   284  			},
   285  			ExpectedWebhook: nil,
   286  			ExpectedErr:     testErr,
   287  		},
   288  	}
   289  
   290  	for _, testCase := range testCases {
   291  		t.Run(testCase.Name, func(t *testing.T) {
   292  			var appSvc *automock.ApplicationService
   293  			var appTemplateSvc *automock.ApplicationTemplateService
   294  			var runtimeSvc *automock.RuntimeService
   295  			var formationTemplateSvc *automock.FormationTemplateService
   296  			svc := testCase.ServiceFn()
   297  			if testCase.AppServiceFn != nil {
   298  				appSvc = testCase.AppServiceFn()
   299  			}
   300  			if testCase.AppTemplateServiceFn != nil {
   301  				appTemplateSvc = testCase.AppTemplateServiceFn()
   302  			}
   303  			if testCase.RuntimeServiceFn != nil {
   304  				runtimeSvc = testCase.RuntimeServiceFn()
   305  			}
   306  			if testCase.FormationTemplateServiceFn != nil {
   307  				formationTemplateSvc = testCase.FormationTemplateServiceFn()
   308  			}
   309  
   310  			converter := testCase.ConverterFn()
   311  
   312  			persistTxMock := testCase.PersistenceFn()
   313  			transactionerMock := testCase.TransactionerFn(persistTxMock)
   314  
   315  			resolver := webhook.NewResolver(transactionerMock, svc, appSvc, appTemplateSvc, runtimeSvc, formationTemplateSvc, converter)
   316  
   317  			// WHEN
   318  			var err error
   319  			var result *graphql.Webhook
   320  			if testCase.AppServiceFn != nil {
   321  				result, err = resolver.AddWebhook(context.TODO(), stringPtr(givenAppID), nil, nil, nil, *gqlWebhookInput)
   322  			}
   323  			if testCase.AppTemplateServiceFn != nil {
   324  				result, err = resolver.AddWebhook(context.TODO(), nil, stringPtr(givenAppTemplateID), nil, nil, *gqlWebhookInput)
   325  			}
   326  			if testCase.RuntimeServiceFn != nil {
   327  				result, err = resolver.AddWebhook(context.TODO(), nil, nil, stringPtr(givenRuntimeID), nil, *gqlWebhookInput)
   328  			}
   329  			if testCase.FormationTemplateServiceFn != nil {
   330  				result, err = resolver.AddWebhook(context.TODO(), nil, nil, nil, stringPtr(givenFormationTemplateID), *gqlWebhookInput)
   331  			}
   332  
   333  			// THEN
   334  			assert.Equal(t, testCase.ExpectedWebhook, result)
   335  			if testCase.ExpectedErr == nil {
   336  				require.NoError(t, err)
   337  			} else {
   338  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
   339  			}
   340  
   341  			svc.AssertExpectations(t)
   342  			if testCase.AppServiceFn != nil {
   343  				appSvc.AssertExpectations(t)
   344  			}
   345  			if testCase.AppTemplateServiceFn != nil {
   346  				appTemplateSvc.AssertExpectations(t)
   347  			}
   348  			if testCase.RuntimeServiceFn != nil {
   349  				runtimeSvc.AssertExpectations(t)
   350  			}
   351  			if testCase.FormationTemplateServiceFn != nil {
   352  				formationTemplateSvc.AssertExpectations(t)
   353  			}
   354  			converter.AssertExpectations(t)
   355  			persistTxMock.AssertExpectations(t)
   356  			transactionerMock.AssertExpectations(t)
   357  		})
   358  		t.Run("Error when more than one of application, application_template, runtime, formation_template is specified", func(t *testing.T) {
   359  			persistTxMock := txtest.PersistenceContextThatDoesntExpectCommit()
   360  			transactionerMock := txtest.TransactionerThatSucceeds(persistTxMock)
   361  
   362  			resolver := webhook.NewResolver(transactionerMock, nil, nil, nil, nil, nil, nil)
   363  			_, err := resolver.AddWebhook(context.TODO(), stringPtr("app"), stringPtr("app_template"), stringPtr("runtime"), stringPtr("formation_template"), graphql.WebhookInput{})
   364  			assert.Error(t, err)
   365  			assert.Contains(t, err.Error(), "exactly one of applicationID, applicationTemplateID, runtimeID or formationTemplateID should be specified")
   366  		})
   367  		t.Run("Error when none of application, application_template, runtime, formation_template is specified", func(t *testing.T) {
   368  			persistTxMock := txtest.PersistenceContextThatDoesntExpectCommit()
   369  			transactionerMock := txtest.TransactionerThatSucceeds(persistTxMock)
   370  
   371  			resolver := webhook.NewResolver(transactionerMock, nil, nil, nil, nil, nil, nil)
   372  			_, err := resolver.AddWebhook(context.TODO(), nil, nil, nil, nil, graphql.WebhookInput{})
   373  			assert.Error(t, err)
   374  			assert.Contains(t, err.Error(), "exactly one of applicationID, applicationTemplateID, runtimeID or formationTemplateID should be specified")
   375  		})
   376  	}
   377  }
   378  
   379  func TestResolver_UpdateWebhook(t *testing.T) {
   380  	// GIVEN
   381  	testErr := errors.New("Test error")
   382  
   383  	applicationID := "foo"
   384  	givenWebhookID := "bar"
   385  	gqlWebhookInput := fixGQLWebhookInput("foo")
   386  	modelWebhookInput := fixModelWebhookInput("foo")
   387  	gqlWebhook := fixApplicationGQLWebhook(givenWebhookID, "", "")
   388  	modelWebhook := fixApplicationModelWebhook(givenWebhookID, applicationID, givenTenant(), "foo", time.Time{})
   389  
   390  	testCases := []struct {
   391  		Name            string
   392  		ServiceFn       func() *automock.WebhookService
   393  		ConverterFn     func() *automock.WebhookConverter
   394  		PersistenceFn   func() *persistenceautomock.PersistenceTx
   395  		TransactionerFn func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner
   396  		ExpectedWebhook *graphql.Webhook
   397  		ExpectedErr     error
   398  	}{
   399  		{
   400  			Name:            "Success",
   401  			PersistenceFn:   txtest.PersistenceContextThatExpectsCommit,
   402  			TransactionerFn: txtest.TransactionerThatSucceeds,
   403  			ServiceFn: func() *automock.WebhookService {
   404  				svc := &automock.WebhookService{}
   405  				svc.On("Update", txtest.CtxWithDBMatcher(), givenWebhookID, *modelWebhookInput, model.UnknownWebhookReference).Return(nil).Once()
   406  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(modelWebhook, nil).Once()
   407  				return svc
   408  			},
   409  			ConverterFn: func() *automock.WebhookConverter {
   410  				conv := &automock.WebhookConverter{}
   411  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   412  				conv.On("ToGraphQL", modelWebhook).Return(gqlWebhook, nil).Once()
   413  				return conv
   414  			},
   415  			ExpectedWebhook: gqlWebhook,
   416  			ExpectedErr:     nil,
   417  		},
   418  		{
   419  			Name:          "Returns error on starting transaction",
   420  			PersistenceFn: txtest.PersistenceContextThatDoesntExpectCommit,
   421  			TransactionerFn: func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner {
   422  				transact := &persistenceautomock.Transactioner{}
   423  				transact.On("Begin").Return(persistTx, givenError()).Once()
   424  				return transact
   425  			},
   426  			ServiceFn: func() *automock.WebhookService {
   427  				return &automock.WebhookService{}
   428  			},
   429  			ConverterFn: func() *automock.WebhookConverter {
   430  				return &automock.WebhookConverter{}
   431  			},
   432  			ExpectedErr: givenError(),
   433  		},
   434  		{
   435  			Name: "Returns error on committing transaction",
   436  			PersistenceFn: func() *persistenceautomock.PersistenceTx {
   437  				persistTx := &persistenceautomock.PersistenceTx{}
   438  				persistTx.On("Commit").Return(givenError()).Once()
   439  				return persistTx
   440  			},
   441  			TransactionerFn: txtest.TransactionerThatSucceeds,
   442  			ServiceFn: func() *automock.WebhookService {
   443  				svc := &automock.WebhookService{}
   444  				svc.On("Update", txtest.CtxWithDBMatcher(), givenWebhookID, *modelWebhookInput, model.UnknownWebhookReference).Return(nil).Once()
   445  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(modelWebhook, nil).Once()
   446  				return svc
   447  			},
   448  			ConverterFn: func() *automock.WebhookConverter {
   449  				conv := &automock.WebhookConverter{}
   450  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   451  				return conv
   452  			},
   453  			ExpectedErr: givenError(),
   454  		},
   455  		{
   456  			Name:            "Returns error when webhook conversion failed",
   457  			TransactionerFn: txtest.TransactionerThatSucceeds,
   458  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   459  			ServiceFn: func() *automock.WebhookService {
   460  				return &automock.WebhookService{}
   461  			},
   462  			ConverterFn: func() *automock.WebhookConverter {
   463  				conv := &automock.WebhookConverter{}
   464  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(nil, testErr).Once()
   465  				return conv
   466  			},
   467  			ExpectedWebhook: nil,
   468  			ExpectedErr:     errors.New("while converting the WebhookInput"),
   469  		},
   470  		{
   471  			Name:            "Returns error when webhook update failed",
   472  			TransactionerFn: txtest.TransactionerThatSucceeds,
   473  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   474  			ServiceFn: func() *automock.WebhookService {
   475  				svc := &automock.WebhookService{}
   476  				svc.On("Update", txtest.CtxWithDBMatcher(), givenWebhookID, *modelWebhookInput, model.UnknownWebhookReference).Return(testErr).Once()
   477  				return svc
   478  			},
   479  			ConverterFn: func() *automock.WebhookConverter {
   480  				conv := &automock.WebhookConverter{}
   481  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   482  				return conv
   483  			},
   484  			ExpectedWebhook: nil,
   485  			ExpectedErr:     testErr,
   486  		},
   487  		{
   488  			Name:            "Returns error when webhook retrieval failed",
   489  			TransactionerFn: txtest.TransactionerThatSucceeds,
   490  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   491  			ServiceFn: func() *automock.WebhookService {
   492  				svc := &automock.WebhookService{}
   493  				svc.On("Update", txtest.CtxWithDBMatcher(), givenWebhookID, *modelWebhookInput, model.UnknownWebhookReference).Return(nil).Once()
   494  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(nil, testErr).Once()
   495  				return svc
   496  			},
   497  			ConverterFn: func() *automock.WebhookConverter {
   498  				conv := &automock.WebhookConverter{}
   499  				conv.On("InputFromGraphQL", gqlWebhookInput).Return(modelWebhookInput, nil).Once()
   500  				return conv
   501  			},
   502  			ExpectedWebhook: nil,
   503  			ExpectedErr:     testErr,
   504  		},
   505  	}
   506  
   507  	for _, testCase := range testCases {
   508  		t.Run(testCase.Name, func(t *testing.T) {
   509  			svc := testCase.ServiceFn()
   510  			converter := testCase.ConverterFn()
   511  
   512  			persistTxMock := testCase.PersistenceFn()
   513  			transactionerMock := testCase.TransactionerFn(persistTxMock)
   514  
   515  			resolver := webhook.NewResolver(transactionerMock, svc, nil, nil, nil, nil, converter)
   516  
   517  			// WHEN
   518  			result, err := resolver.UpdateWebhook(context.TODO(), givenWebhookID, *gqlWebhookInput)
   519  
   520  			// THEN
   521  			assert.Equal(t, testCase.ExpectedWebhook, result)
   522  			if testCase.ExpectedErr != nil {
   523  				assert.Error(t, err)
   524  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
   525  			}
   526  			svc.AssertExpectations(t)
   527  			converter.AssertExpectations(t)
   528  			transactionerMock.AssertExpectations(t)
   529  		})
   530  	}
   531  }
   532  
   533  func TestResolver_DeleteWebhook(t *testing.T) {
   534  	// GIVEN
   535  	testErr := errors.New("Test error")
   536  
   537  	applicationID := "foo"
   538  	givenWebhookID := "bar"
   539  
   540  	gqlWebhook := fixApplicationGQLWebhook(givenWebhookID, "", "")
   541  	modelWebhook := fixApplicationModelWebhook(givenWebhookID, applicationID, givenTenant(), "foo", time.Time{})
   542  
   543  	testCases := []struct {
   544  		Name            string
   545  		ServiceFn       func() *automock.WebhookService
   546  		ConverterFn     func() *automock.WebhookConverter
   547  		PersistenceFn   func() *persistenceautomock.PersistenceTx
   548  		TransactionerFn func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner
   549  		ExpectedWebhook *graphql.Webhook
   550  		ExpectedErr     error
   551  	}{
   552  		{
   553  			Name:            "Success",
   554  			TransactionerFn: txtest.TransactionerThatSucceeds,
   555  			PersistenceFn:   txtest.PersistenceContextThatExpectsCommit,
   556  			ServiceFn: func() *automock.WebhookService {
   557  				svc := &automock.WebhookService{}
   558  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(modelWebhook, nil).Once()
   559  				svc.On("Delete", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(nil).Once()
   560  				return svc
   561  			},
   562  			ConverterFn: func() *automock.WebhookConverter {
   563  				conv := &automock.WebhookConverter{}
   564  				conv.On("ToGraphQL", modelWebhook).Return(gqlWebhook, nil).Once()
   565  				return conv
   566  			},
   567  			ExpectedWebhook: gqlWebhook,
   568  			ExpectedErr:     nil,
   569  		},
   570  		{
   571  			Name:          "Returns error on starting transaction",
   572  			PersistenceFn: txtest.PersistenceContextThatDoesntExpectCommit,
   573  			TransactionerFn: func(persistTx *persistenceautomock.PersistenceTx) *persistenceautomock.Transactioner {
   574  				transact := &persistenceautomock.Transactioner{}
   575  				transact.On("Begin").Return(persistTx, givenError()).Once()
   576  				return transact
   577  			},
   578  			ServiceFn: func() *automock.WebhookService {
   579  				return &automock.WebhookService{}
   580  			},
   581  
   582  			ConverterFn: func() *automock.WebhookConverter {
   583  				return &automock.WebhookConverter{}
   584  			},
   585  			ExpectedErr: givenError(),
   586  		},
   587  		{
   588  			Name: "Returns error on committing transaction",
   589  			PersistenceFn: func() *persistenceautomock.PersistenceTx {
   590  				persistTx := &persistenceautomock.PersistenceTx{}
   591  				persistTx.On("Commit").Return(givenError()).Once()
   592  				return persistTx
   593  			},
   594  			TransactionerFn: txtest.TransactionerThatSucceeds,
   595  			ServiceFn: func() *automock.WebhookService {
   596  				svc := &automock.WebhookService{}
   597  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(modelWebhook, nil).Once()
   598  				svc.On("Delete", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(nil).Once()
   599  				return svc
   600  			},
   601  			ConverterFn: func() *automock.WebhookConverter {
   602  				conv := &automock.WebhookConverter{}
   603  				conv.On("ToGraphQL", modelWebhook).Return(gqlWebhook, nil).Once()
   604  				return conv
   605  			},
   606  			ExpectedErr: givenError(),
   607  		},
   608  		{
   609  			Name:            "Returns error when webhook retrieval failed",
   610  			TransactionerFn: txtest.TransactionerThatSucceeds,
   611  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   612  			ServiceFn: func() *automock.WebhookService {
   613  				svc := &automock.WebhookService{}
   614  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(nil, testErr).Once()
   615  				return svc
   616  			},
   617  			ConverterFn: func() *automock.WebhookConverter {
   618  				conv := &automock.WebhookConverter{}
   619  				return conv
   620  			},
   621  			ExpectedWebhook: nil,
   622  			ExpectedErr:     testErr,
   623  		},
   624  		{
   625  			Name:            "Returns error when webhook deletion failed",
   626  			TransactionerFn: txtest.TransactionerThatSucceeds,
   627  			PersistenceFn:   txtest.PersistenceContextThatDoesntExpectCommit,
   628  			ServiceFn: func() *automock.WebhookService {
   629  				svc := &automock.WebhookService{}
   630  				svc.On("Get", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(modelWebhook, nil).Once()
   631  				svc.On("Delete", txtest.CtxWithDBMatcher(), givenWebhookID, model.UnknownWebhookReference).Return(testErr).Once()
   632  				return svc
   633  			},
   634  			ConverterFn: func() *automock.WebhookConverter {
   635  				conv := &automock.WebhookConverter{}
   636  				conv.On("ToGraphQL", modelWebhook).Return(gqlWebhook, nil).Once()
   637  				return conv
   638  			},
   639  			ExpectedWebhook: nil,
   640  			ExpectedErr:     testErr,
   641  		},
   642  	}
   643  
   644  	for _, testCase := range testCases {
   645  		t.Run(testCase.Name, func(t *testing.T) {
   646  			svc := testCase.ServiceFn()
   647  			converter := testCase.ConverterFn()
   648  
   649  			persistTxMock := testCase.PersistenceFn()
   650  			transactionerMock := testCase.TransactionerFn(persistTxMock)
   651  
   652  			resolver := webhook.NewResolver(transactionerMock, svc, nil, nil, nil, nil, converter)
   653  
   654  			// WHEN
   655  			result, err := resolver.DeleteWebhook(context.TODO(), givenWebhookID)
   656  
   657  			// THEN
   658  			assert.Equal(t, testCase.ExpectedWebhook, result)
   659  			assert.Equal(t, testCase.ExpectedErr, err)
   660  
   661  			svc.AssertExpectations(t)
   662  			converter.AssertExpectations(t)
   663  			transactionerMock.AssertExpectations(t)
   664  		})
   665  	}
   666  }