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

     1  package spec_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/internal/domain/spec"
    10  	"github.com/kyma-incubator/compass/components/director/internal/domain/spec/automock"
    11  	tnt "github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
    12  	"github.com/kyma-incubator/compass/components/director/internal/model"
    13  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    15  	"github.com/pkg/errors"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/mock"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  const tenantID = "b91b59f7-2563-40b2-aba9-fef726037aa3"
    22  
    23  var testErr = errors.New("Test error")
    24  
    25  func TestService_GetByID(t *testing.T) {
    26  	testSpec := &model.Spec{}
    27  
    28  	testCases := []struct {
    29  		Name           string
    30  		Context        context.Context
    31  		SpecRepoMock   *automock.SpecRepository
    32  		ExpectedResult *model.Spec
    33  		ExpectedError  error
    34  	}{
    35  		{
    36  			Name:    "Success",
    37  			Context: tnt.SaveToContext(context.TODO(), tenantID, tenantID),
    38  			SpecRepoMock: func() *automock.SpecRepository {
    39  				specRepositoryMock := automock.SpecRepository{}
    40  				specRepositoryMock.On("GetByID", mock.Anything, tenantID, mock.Anything, mock.Anything).Return(testSpec, nil).Once()
    41  				return &specRepositoryMock
    42  			}(),
    43  			ExpectedResult: testSpec,
    44  			ExpectedError:  nil,
    45  		},
    46  		{
    47  			Name:           "Fails when tenant is missing in context",
    48  			Context:        context.TODO(),
    49  			SpecRepoMock:   &automock.SpecRepository{},
    50  			ExpectedResult: nil,
    51  			ExpectedError:  apperrors.NewCannotReadTenantError(),
    52  		},
    53  		{
    54  			Name:    "Fails when repo get by id fails",
    55  			Context: tnt.SaveToContext(context.TODO(), tenantID, tenantID),
    56  			SpecRepoMock: func() *automock.SpecRepository {
    57  				specRepositoryMock := automock.SpecRepository{}
    58  				specRepositoryMock.On("GetByID", mock.Anything, tenantID, mock.Anything, mock.Anything).Return(nil, testErr).Once()
    59  				return &specRepositoryMock
    60  			}(),
    61  			ExpectedResult: testSpec,
    62  			ExpectedError:  testErr,
    63  		},
    64  	}
    65  
    66  	for _, testCase := range testCases {
    67  		t.Run(testCase.Name, func(t *testing.T) {
    68  			repo := testCase.SpecRepoMock
    69  			svc := spec.NewService(repo, nil, nil, nil)
    70  
    71  			// WHEN
    72  			spec, err := svc.GetByID(testCase.Context, "123", model.APISpecReference)
    73  
    74  			// then
    75  			if testCase.ExpectedError == nil {
    76  				require.NoError(t, err)
    77  				assert.Equal(t, testCase.ExpectedResult, spec)
    78  			} else {
    79  				require.Error(t, err)
    80  				assert.Equal(t, err, testCase.ExpectedError)
    81  			}
    82  
    83  			repo.AssertExpectations(t)
    84  		})
    85  	}
    86  }
    87  
    88  func TestService_GetByIDGlobal(t *testing.T) {
    89  	testSpec := &model.Spec{}
    90  
    91  	testCases := []struct {
    92  		Name           string
    93  		SpecRepoMock   *automock.SpecRepository
    94  		ExpectedResult *model.Spec
    95  		ExpectedError  error
    96  	}{
    97  		{
    98  			Name: "Success",
    99  			SpecRepoMock: func() *automock.SpecRepository {
   100  				specRepositoryMock := automock.SpecRepository{}
   101  				specRepositoryMock.On("GetByIDGlobal", mock.Anything, specID).Return(testSpec, nil).Once()
   102  				return &specRepositoryMock
   103  			}(),
   104  			ExpectedResult: testSpec,
   105  			ExpectedError:  nil,
   106  		},
   107  		{
   108  			Name: "Fails when repo get by id fails",
   109  			SpecRepoMock: func() *automock.SpecRepository {
   110  				specRepositoryMock := automock.SpecRepository{}
   111  				specRepositoryMock.On("GetByIDGlobal", mock.Anything, specID).Return(nil, testErr).Once()
   112  				return &specRepositoryMock
   113  			}(),
   114  			ExpectedResult: testSpec,
   115  			ExpectedError:  testErr,
   116  		},
   117  	}
   118  
   119  	for _, testCase := range testCases {
   120  		t.Run(testCase.Name, func(t *testing.T) {
   121  			repo := testCase.SpecRepoMock
   122  			svc := spec.NewService(repo, nil, nil, nil)
   123  
   124  			// WHEN
   125  			spec, err := svc.GetByIDGlobal(context.TODO(), specID)
   126  
   127  			// then
   128  			if testCase.ExpectedError == nil {
   129  				require.NoError(t, err)
   130  				assert.Equal(t, testCase.ExpectedResult, spec)
   131  			} else {
   132  				require.Error(t, err)
   133  				assert.Equal(t, err, testCase.ExpectedError)
   134  			}
   135  
   136  			repo.AssertExpectations(t)
   137  		})
   138  	}
   139  }
   140  
   141  func TestService_ListIDByReferenceObjectID(t *testing.T) {
   142  	// GIVEN
   143  	specIDs := []string{specID}
   144  
   145  	ctx := context.TODO()
   146  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   147  
   148  	testCases := []struct {
   149  		Name               string
   150  		RepositoryFn       func() *automock.SpecRepository
   151  		ResourceType       resource.Type
   152  		ExpectedResult     []string
   153  		ExpectedErrMessage string
   154  	}{
   155  		{
   156  			Name: "Success for Application",
   157  			RepositoryFn: func() *automock.SpecRepository {
   158  				repo := &automock.SpecRepository{}
   159  				repo.On("ListIDByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(specIDs, nil).Once()
   160  				return repo
   161  			},
   162  			ResourceType:       resource.Application,
   163  			ExpectedResult:     specIDs,
   164  			ExpectedErrMessage: "",
   165  		},
   166  		{
   167  			Name: "Success for Application Template Version",
   168  			RepositoryFn: func() *automock.SpecRepository {
   169  				repo := &automock.SpecRepository{}
   170  				repo.On("ListIDByReferenceObjectIDGlobal", ctx, model.APISpecReference, apiID).Return(specIDs, nil).Once()
   171  				return repo
   172  			},
   173  			ResourceType:       resource.ApplicationTemplateVersion,
   174  			ExpectedResult:     specIDs,
   175  			ExpectedErrMessage: "",
   176  		},
   177  		{
   178  			Name: "Returns error when APIDefinition listing failed for Application",
   179  			RepositoryFn: func() *automock.SpecRepository {
   180  				repo := &automock.SpecRepository{}
   181  				repo.On("ListIDByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(nil, testErr).Once()
   182  				return repo
   183  			},
   184  			ResourceType:       resource.Application,
   185  			ExpectedResult:     nil,
   186  			ExpectedErrMessage: testErr.Error(),
   187  		},
   188  		{
   189  			Name: "Returns error when APIDefinition listing failed for Application Template Version",
   190  			RepositoryFn: func() *automock.SpecRepository {
   191  				repo := &automock.SpecRepository{}
   192  				repo.On("ListIDByReferenceObjectIDGlobal", ctx, model.APISpecReference, apiID).Return(nil, testErr).Once()
   193  				return repo
   194  			},
   195  			ResourceType:       resource.ApplicationTemplateVersion,
   196  			ExpectedResult:     nil,
   197  			ExpectedErrMessage: testErr.Error(),
   198  		},
   199  	}
   200  
   201  	for _, testCase := range testCases {
   202  		t.Run(testCase.Name, func(t *testing.T) {
   203  			repo := testCase.RepositoryFn()
   204  
   205  			svc := spec.NewService(repo, nil, nil, nil)
   206  
   207  			// WHEN
   208  			ids, err := svc.ListIDByReferenceObjectID(ctx, testCase.ResourceType, model.APISpecReference, apiID)
   209  
   210  			// then
   211  			if testCase.ExpectedErrMessage == "" {
   212  				require.NoError(t, err)
   213  				assert.Equal(t, testCase.ExpectedResult, ids)
   214  			} else {
   215  				require.Error(t, err)
   216  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   217  			}
   218  
   219  			repo.AssertExpectations(t)
   220  		})
   221  	}
   222  	t.Run("Error when tenant not in context", func(t *testing.T) {
   223  		svc := spec.NewService(nil, nil, nil, nil)
   224  		// WHEN
   225  		_, err := svc.ListIDByReferenceObjectID(context.TODO(), resource.Application, model.APISpecReference, apiID)
   226  		// THEN
   227  		require.Error(t, err)
   228  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   229  	})
   230  }
   231  
   232  func TestService_ListByReferenceObjectID(t *testing.T) {
   233  	// GIVEN
   234  	specs := []*model.Spec{
   235  		fixModelAPISpec(),
   236  		fixModelAPISpec(),
   237  		fixModelAPISpec(),
   238  	}
   239  
   240  	ctx := context.TODO()
   241  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   242  
   243  	testCases := []struct {
   244  		Name               string
   245  		RepositoryFn       func() *automock.SpecRepository
   246  		ExpectedResult     []*model.Spec
   247  		ExpectedErrMessage string
   248  	}{
   249  		{
   250  			Name: "Success",
   251  			RepositoryFn: func() *automock.SpecRepository {
   252  				repo := &automock.SpecRepository{}
   253  				repo.On("ListByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(specs, nil).Once()
   254  				return repo
   255  			},
   256  			ExpectedResult:     specs,
   257  			ExpectedErrMessage: "",
   258  		},
   259  		{
   260  			Name: "Returns error when APIDefinition listing failed",
   261  			RepositoryFn: func() *automock.SpecRepository {
   262  				repo := &automock.SpecRepository{}
   263  				repo.On("ListByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(nil, testErr).Once()
   264  				return repo
   265  			},
   266  			ExpectedResult:     nil,
   267  			ExpectedErrMessage: testErr.Error(),
   268  		},
   269  	}
   270  
   271  	for _, testCase := range testCases {
   272  		t.Run(testCase.Name, func(t *testing.T) {
   273  			repo := testCase.RepositoryFn()
   274  
   275  			svc := spec.NewService(repo, nil, nil, nil)
   276  
   277  			// WHEN
   278  			docs, err := svc.ListByReferenceObjectID(ctx, model.APISpecReference, apiID)
   279  
   280  			// then
   281  			if testCase.ExpectedErrMessage == "" {
   282  				require.NoError(t, err)
   283  				assert.Equal(t, testCase.ExpectedResult, docs)
   284  			} else {
   285  				require.Error(t, err)
   286  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   287  			}
   288  
   289  			repo.AssertExpectations(t)
   290  		})
   291  	}
   292  	t.Run("Error when tenant not in context", func(t *testing.T) {
   293  		svc := spec.NewService(nil, nil, nil, nil)
   294  		// WHEN
   295  		_, err := svc.ListByReferenceObjectID(context.TODO(), model.APISpecReference, apiID)
   296  		// THEN
   297  		require.Error(t, err)
   298  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   299  	})
   300  }
   301  
   302  func TestService_ListByReferenceObjectIDs(t *testing.T) {
   303  	// GIVEN
   304  	testErr := errors.New("Test error")
   305  	firstAPIID := "apiID"
   306  	secondAPIID := "apiID2"
   307  	apiIDs := []string{firstAPIID, secondAPIID}
   308  
   309  	specForFirstAPI := fixModelAPISpecWithID(firstAPIID)
   310  	specForSecondAPI := fixModelAPISpecWithID(secondAPIID)
   311  	specs := []*model.Spec{specForFirstAPI, specForSecondAPI}
   312  
   313  	ctx := context.TODO()
   314  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   315  
   316  	testCases := []struct {
   317  		Name               string
   318  		RepositoryFn       func() *automock.SpecRepository
   319  		ExpectedResult     []*model.Spec
   320  		ExpectedErrMessage string
   321  	}{
   322  		{
   323  			Name: "Success",
   324  			RepositoryFn: func() *automock.SpecRepository {
   325  				repo := &automock.SpecRepository{}
   326  				repo.On("ListByReferenceObjectIDs", ctx, tenant, model.APISpecReference, apiIDs).Return(specs, nil).Once()
   327  				return repo
   328  			},
   329  			ExpectedResult: specs,
   330  		},
   331  		{
   332  			Name: "Returns error when Specs listing failed",
   333  			RepositoryFn: func() *automock.SpecRepository {
   334  				repo := &automock.SpecRepository{}
   335  				repo.On("ListByReferenceObjectIDs", ctx, tenant, model.APISpecReference, apiIDs).Return(nil, testErr).Once()
   336  				return repo
   337  			},
   338  			ExpectedResult:     nil,
   339  			ExpectedErrMessage: testErr.Error(),
   340  		},
   341  	}
   342  
   343  	for _, testCase := range testCases {
   344  		t.Run(testCase.Name, func(t *testing.T) {
   345  			repo := testCase.RepositoryFn()
   346  
   347  			svc := spec.NewService(repo, nil, nil, nil)
   348  
   349  			// WHEN
   350  			specifications, err := svc.ListByReferenceObjectIDs(ctx, model.APISpecReference, apiIDs)
   351  
   352  			// then
   353  			if testCase.ExpectedErrMessage == "" {
   354  				require.NoError(t, err)
   355  				assert.Equal(t, testCase.ExpectedResult, specifications)
   356  			} else {
   357  				require.Error(t, err)
   358  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   359  			}
   360  
   361  			repo.AssertExpectations(t)
   362  		})
   363  	}
   364  	t.Run("Error when tenant not in context", func(t *testing.T) {
   365  		svc := spec.NewService(nil, nil, nil, nil)
   366  		// WHEN
   367  		_, err := svc.ListByReferenceObjectIDs(context.TODO(), model.APISpecReference, apiIDs)
   368  		// THEN
   369  		require.Error(t, err)
   370  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   371  	})
   372  }
   373  
   374  func TestService_DeleteByReferenceObjectID(t *testing.T) {
   375  	// GIVEN
   376  	testErr := errors.New("Test error")
   377  
   378  	specs := []*model.Spec{
   379  		fixModelAPISpec(),
   380  		fixModelAPISpec(),
   381  		fixModelAPISpec(),
   382  	}
   383  
   384  	ctx := context.TODO()
   385  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   386  
   387  	testCases := []struct {
   388  		Name               string
   389  		RepositoryFn       func() *automock.SpecRepository
   390  		ExpectedResult     []*model.Spec
   391  		ResourceType       resource.Type
   392  		ExpectedErrMessage string
   393  	}{
   394  		{
   395  			Name: "Success for Application",
   396  			RepositoryFn: func() *automock.SpecRepository {
   397  				repo := &automock.SpecRepository{}
   398  				repo.On("DeleteByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(nil).Once()
   399  				return repo
   400  			},
   401  			ResourceType:       resource.Application,
   402  			ExpectedResult:     specs,
   403  			ExpectedErrMessage: "",
   404  		},
   405  		{
   406  			Name: "Success for Application Template Version",
   407  			RepositoryFn: func() *automock.SpecRepository {
   408  				repo := &automock.SpecRepository{}
   409  				repo.On("DeleteByReferenceObjectIDGlobal", ctx, model.APISpecReference, apiID).Return(nil).Once()
   410  				return repo
   411  			},
   412  			ResourceType:       resource.ApplicationTemplateVersion,
   413  			ExpectedResult:     specs,
   414  			ExpectedErrMessage: "",
   415  		},
   416  		{
   417  			Name: "Returns error when APIDefinition listing failed for Application",
   418  			RepositoryFn: func() *automock.SpecRepository {
   419  				repo := &automock.SpecRepository{}
   420  				repo.On("DeleteByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(testErr).Once()
   421  				return repo
   422  			},
   423  			ResourceType:       resource.Application,
   424  			ExpectedResult:     nil,
   425  			ExpectedErrMessage: testErr.Error(),
   426  		},
   427  		{
   428  			Name: "Returns error when APIDefinition listing failed for Application",
   429  			RepositoryFn: func() *automock.SpecRepository {
   430  				repo := &automock.SpecRepository{}
   431  				repo.On("DeleteByReferenceObjectIDGlobal", ctx, model.APISpecReference, apiID).Return(testErr).Once()
   432  				return repo
   433  			},
   434  			ResourceType:       resource.ApplicationTemplateVersion,
   435  			ExpectedResult:     nil,
   436  			ExpectedErrMessage: testErr.Error(),
   437  		},
   438  	}
   439  
   440  	for _, testCase := range testCases {
   441  		t.Run(testCase.Name, func(t *testing.T) {
   442  			repo := testCase.RepositoryFn()
   443  
   444  			svc := spec.NewService(repo, nil, nil, nil)
   445  
   446  			// WHEN
   447  			err := svc.DeleteByReferenceObjectID(ctx, testCase.ResourceType, model.APISpecReference, apiID)
   448  
   449  			// then
   450  			if testCase.ExpectedErrMessage == "" {
   451  				require.NoError(t, err)
   452  			} else {
   453  				require.Error(t, err)
   454  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   455  			}
   456  
   457  			repo.AssertExpectations(t)
   458  		})
   459  	}
   460  	t.Run("Error when tenant not in context", func(t *testing.T) {
   461  		svc := spec.NewService(nil, nil, nil, nil)
   462  		// WHEN
   463  		err := svc.DeleteByReferenceObjectID(context.TODO(), resource.Application, model.APISpecReference, apiID)
   464  		// THEN
   465  		require.Error(t, err)
   466  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   467  	})
   468  }
   469  
   470  func TestService_GetByReferenceObjectID(t *testing.T) {
   471  	// GIVEN
   472  	testErr := errors.New("Test error")
   473  
   474  	specs := []*model.Spec{
   475  		fixModelAPISpec(),
   476  		fixModelAPISpec(),
   477  		fixModelAPISpec(),
   478  	}
   479  
   480  	ctx := context.TODO()
   481  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   482  
   483  	testCases := []struct {
   484  		Name               string
   485  		RepositoryFn       func() *automock.SpecRepository
   486  		ResourceType       resource.Type
   487  		ExpectedResult     *model.Spec
   488  		ExpectedErrMessage string
   489  	}{
   490  		{
   491  			Name: "Success for Application",
   492  			RepositoryFn: func() *automock.SpecRepository {
   493  				repo := &automock.SpecRepository{}
   494  				repo.On("ListByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(specs, nil).Once()
   495  				return repo
   496  			},
   497  			ResourceType:       resource.Application,
   498  			ExpectedResult:     specs[0],
   499  			ExpectedErrMessage: "",
   500  		},
   501  		{
   502  			Name: "Success for Application Template Version",
   503  			RepositoryFn: func() *automock.SpecRepository {
   504  				repo := &automock.SpecRepository{}
   505  				repo.On("ListByReferenceObjectIDGlobal", ctx, model.APISpecReference, apiID).Return(specs, nil).Once()
   506  				return repo
   507  			},
   508  			ResourceType:       resource.ApplicationTemplateVersion,
   509  			ExpectedResult:     specs[0],
   510  			ExpectedErrMessage: "",
   511  		},
   512  		{
   513  			Name: "Returns error when APIDefinition listing failed for Application",
   514  			RepositoryFn: func() *automock.SpecRepository {
   515  				repo := &automock.SpecRepository{}
   516  				repo.On("ListByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return(nil, testErr).Once()
   517  				return repo
   518  			},
   519  			ResourceType:       resource.Application,
   520  			ExpectedResult:     nil,
   521  			ExpectedErrMessage: testErr.Error(),
   522  		},
   523  		{
   524  			Name: "Returns error when APIDefinition listing failed for Application Template Version",
   525  			RepositoryFn: func() *automock.SpecRepository {
   526  				repo := &automock.SpecRepository{}
   527  				repo.On("ListByReferenceObjectIDGlobal", ctx, model.APISpecReference, apiID).Return(nil, testErr).Once()
   528  				return repo
   529  			},
   530  			ResourceType:       resource.ApplicationTemplateVersion,
   531  			ExpectedResult:     nil,
   532  			ExpectedErrMessage: testErr.Error(),
   533  		},
   534  		{
   535  			Name: "Returns nil when no specs are found",
   536  			RepositoryFn: func() *automock.SpecRepository {
   537  				repo := &automock.SpecRepository{}
   538  				repo.On("ListByReferenceObjectID", ctx, tenant, model.APISpecReference, apiID).Return([]*model.Spec{}, nil).Once()
   539  				return repo
   540  			},
   541  			ResourceType:   resource.Application,
   542  			ExpectedResult: nil,
   543  		},
   544  	}
   545  
   546  	for _, testCase := range testCases {
   547  		t.Run(testCase.Name, func(t *testing.T) {
   548  			repo := testCase.RepositoryFn()
   549  
   550  			svc := spec.NewService(repo, nil, nil, nil)
   551  
   552  			// WHEN
   553  			docs, err := svc.GetByReferenceObjectID(ctx, testCase.ResourceType, model.APISpecReference, apiID)
   554  
   555  			// then
   556  			if testCase.ExpectedErrMessage == "" {
   557  				require.NoError(t, err)
   558  				assert.Equal(t, testCase.ExpectedResult, docs)
   559  			} else {
   560  				require.Error(t, err)
   561  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
   562  			}
   563  
   564  			repo.AssertExpectations(t)
   565  		})
   566  	}
   567  	t.Run("Error when tenant not in context", func(t *testing.T) {
   568  		svc := spec.NewService(nil, nil, nil, nil)
   569  		// WHEN
   570  		_, err := svc.GetByReferenceObjectID(context.TODO(), resource.Application, model.APISpecReference, apiID)
   571  		// THEN
   572  		require.Error(t, err)
   573  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   574  	})
   575  }
   576  
   577  func TestService_CreateByReferenceObjectID(t *testing.T) {
   578  	// GIVEN
   579  	testErr := errors.New("Test error")
   580  
   581  	ctx := context.TODO()
   582  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   583  
   584  	specData := "specData"
   585  
   586  	specInputWithFR := fixModelAPISpecInputWithFetchRequest()
   587  	specInputWithFR.Data = nil
   588  
   589  	specModel := fixModelAPISpec()
   590  	specModel.Data = nil
   591  
   592  	timestamp := time.Now()
   593  
   594  	fr := &model.FetchRequest{
   595  		ID:   specID,
   596  		URL:  "foo.bar",
   597  		Mode: model.FetchModeSingle,
   598  		Status: &model.FetchRequestStatus{
   599  			Condition: model.FetchRequestStatusConditionInitial,
   600  			Timestamp: timestamp,
   601  		},
   602  		ObjectType: model.APISpecFetchRequestReference,
   603  		ObjectID:   specID,
   604  	}
   605  
   606  	testCases := []struct {
   607  		Name                  string
   608  		RepositoryFn          func() *automock.SpecRepository
   609  		FetchRequestRepoFn    func() *automock.FetchRequestRepository
   610  		UIDServiceFn          func() *automock.UIDService
   611  		FetchRequestServiceFn func() *automock.FetchRequestService
   612  		ResourceType          resource.Type
   613  		Input                 model.SpecInput
   614  		ExpectedErr           error
   615  	}{
   616  		{
   617  			Name: "Success for Application",
   618  			RepositoryFn: func() *automock.SpecRepository {
   619  				repo := &automock.SpecRepository{}
   620  				repo.On("Create", ctx, tenant, specModel).Return(nil).Once()
   621  				repo.On("Update", ctx, tenant, specModel).Return(nil).Once()
   622  				return repo
   623  			},
   624  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   625  				repo := &automock.FetchRequestRepository{}
   626  				repo.On("Create", ctx, tenant, fr).Return(nil).Once()
   627  
   628  				return repo
   629  			},
   630  			UIDServiceFn: func() *automock.UIDService {
   631  				svc := &automock.UIDService{}
   632  				svc.On("Generate").Return(specID).Twice()
   633  				return svc
   634  			},
   635  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   636  				svc := &automock.FetchRequestService{}
   637  				svc.On("HandleSpec", ctx, fr).Return(nil)
   638  				return svc
   639  			},
   640  			ResourceType: resource.Application,
   641  			Input:        *specInputWithFR,
   642  			ExpectedErr:  nil,
   643  		},
   644  		{
   645  			Name: "Success for Application Template Version",
   646  			RepositoryFn: func() *automock.SpecRepository {
   647  				repo := &automock.SpecRepository{}
   648  				repo.On("CreateGlobal", ctx, specModel).Return(nil).Once()
   649  				repo.On("UpdateGlobal", ctx, specModel).Return(nil).Once()
   650  				return repo
   651  			},
   652  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   653  				repo := &automock.FetchRequestRepository{}
   654  				repo.On("CreateGlobal", ctx, fr).Return(nil).Once()
   655  
   656  				return repo
   657  			},
   658  			UIDServiceFn: func() *automock.UIDService {
   659  				svc := &automock.UIDService{}
   660  				svc.On("Generate").Return(specID).Twice()
   661  				return svc
   662  			},
   663  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   664  				svc := &automock.FetchRequestService{}
   665  				svc.On("HandleSpec", ctx, fr).Return(nil)
   666  				return svc
   667  			},
   668  			ResourceType: resource.ApplicationTemplateVersion,
   669  			Input:        *specInputWithFR,
   670  			ExpectedErr:  nil,
   671  		},
   672  		{
   673  			Name: "Success fetched Spec",
   674  			RepositoryFn: func() *automock.SpecRepository {
   675  				repo := &automock.SpecRepository{}
   676  				repo.On("Create", ctx, tenant, specModel).Return(nil).Once()
   677  				repo.On("Update", ctx, tenant, fixModelAPISpec()).Return(nil).Once()
   678  
   679  				return repo
   680  			},
   681  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   682  				repo := &automock.FetchRequestRepository{}
   683  				repo.On("Create", ctx, tenant, fr).Return(nil).Once()
   684  
   685  				return repo
   686  			},
   687  			UIDServiceFn: func() *automock.UIDService {
   688  				svc := &automock.UIDService{}
   689  				svc.On("Generate").Return(specID).Twice()
   690  				return svc
   691  			},
   692  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   693  				svc := &automock.FetchRequestService{}
   694  				svc.On("HandleSpec", ctx, fr).Return(&specData)
   695  				return svc
   696  			},
   697  			ResourceType: resource.Application,
   698  			Input:        *specInputWithFR,
   699  			ExpectedErr:  nil,
   700  		},
   701  		{
   702  			Name: "Error - Spec Creation for Application",
   703  			RepositoryFn: func() *automock.SpecRepository {
   704  				repo := &automock.SpecRepository{}
   705  				repo.On("Create", ctx, tenant, specModel).Return(testErr).Once()
   706  				return repo
   707  			},
   708  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   709  				return &automock.FetchRequestRepository{}
   710  			},
   711  			UIDServiceFn: func() *automock.UIDService {
   712  				svc := &automock.UIDService{}
   713  				svc.On("Generate").Return(specID).Once()
   714  				return svc
   715  			},
   716  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   717  				return &automock.FetchRequestService{}
   718  			},
   719  			ResourceType: resource.Application,
   720  			Input:        *specInputWithFR,
   721  			ExpectedErr:  testErr,
   722  		},
   723  		{
   724  			Name: "Error - Spec Creation for Application Template Version",
   725  			RepositoryFn: func() *automock.SpecRepository {
   726  				repo := &automock.SpecRepository{}
   727  				repo.On("CreateGlobal", ctx, specModel).Return(testErr).Once()
   728  				return repo
   729  			},
   730  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   731  				return &automock.FetchRequestRepository{}
   732  			},
   733  			UIDServiceFn: func() *automock.UIDService {
   734  				svc := &automock.UIDService{}
   735  				svc.On("Generate").Return(specID).Once()
   736  				return svc
   737  			},
   738  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   739  				return &automock.FetchRequestService{}
   740  			},
   741  			ResourceType: resource.ApplicationTemplateVersion,
   742  			Input:        *specInputWithFR,
   743  			ExpectedErr:  testErr,
   744  		},
   745  		{
   746  			Name: "Error - Fetch Request Creation for Application",
   747  			RepositoryFn: func() *automock.SpecRepository {
   748  				repo := &automock.SpecRepository{}
   749  				repo.On("Create", ctx, tenant, specModel).Return(nil).Once()
   750  				return repo
   751  			},
   752  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   753  				repo := &automock.FetchRequestRepository{}
   754  				repo.On("Create", ctx, tenant, fr).Return(testErr).Once()
   755  				return repo
   756  			},
   757  			UIDServiceFn: func() *automock.UIDService {
   758  				svc := &automock.UIDService{}
   759  				svc.On("Generate").Return(specID).Twice()
   760  				return svc
   761  			},
   762  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   763  				return &automock.FetchRequestService{}
   764  			},
   765  			ResourceType: resource.Application,
   766  			Input:        *specInputWithFR,
   767  			ExpectedErr:  testErr,
   768  		},
   769  		{
   770  			Name: "Error - Fetch Request Creation for Application Template Version",
   771  			RepositoryFn: func() *automock.SpecRepository {
   772  				repo := &automock.SpecRepository{}
   773  				repo.On("CreateGlobal", ctx, specModel).Return(nil).Once()
   774  				return repo
   775  			},
   776  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   777  				repo := &automock.FetchRequestRepository{}
   778  				repo.On("CreateGlobal", ctx, fr).Return(testErr).Once()
   779  				return repo
   780  			},
   781  			UIDServiceFn: func() *automock.UIDService {
   782  				svc := &automock.UIDService{}
   783  				svc.On("Generate").Return(specID).Twice()
   784  				return svc
   785  			},
   786  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   787  				return &automock.FetchRequestService{}
   788  			},
   789  			ResourceType: resource.ApplicationTemplateVersion,
   790  			Input:        *specInputWithFR,
   791  			ExpectedErr:  testErr,
   792  		},
   793  		{
   794  			Name: "Error - Spec Update for Application",
   795  			RepositoryFn: func() *automock.SpecRepository {
   796  				repo := &automock.SpecRepository{}
   797  				repo.On("Create", ctx, tenant, specModel).Return(nil).Once()
   798  				repo.On("Update", ctx, tenant, specModel).Return(testErr).Once()
   799  
   800  				return repo
   801  			},
   802  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   803  				repo := &automock.FetchRequestRepository{}
   804  				repo.On("Create", ctx, tenant, fr).Return(nil).Once()
   805  				return repo
   806  			},
   807  			UIDServiceFn: func() *automock.UIDService {
   808  				svc := &automock.UIDService{}
   809  				svc.On("Generate").Return(specID).Twice()
   810  				return svc
   811  			},
   812  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   813  				svc := &automock.FetchRequestService{}
   814  				svc.On("HandleSpec", ctx, fr).Return(nil)
   815  				return svc
   816  			},
   817  			ResourceType: resource.Application,
   818  			Input:        *specInputWithFR,
   819  			ExpectedErr:  testErr,
   820  		},
   821  		{
   822  			Name: "Error - Spec Update for Application Template Version",
   823  			RepositoryFn: func() *automock.SpecRepository {
   824  				repo := &automock.SpecRepository{}
   825  				repo.On("CreateGlobal", ctx, specModel).Return(nil).Once()
   826  				repo.On("UpdateGlobal", ctx, specModel).Return(testErr).Once()
   827  
   828  				return repo
   829  			},
   830  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   831  				repo := &automock.FetchRequestRepository{}
   832  				repo.On("CreateGlobal", ctx, fr).Return(nil).Once()
   833  				return repo
   834  			},
   835  			UIDServiceFn: func() *automock.UIDService {
   836  				svc := &automock.UIDService{}
   837  				svc.On("Generate").Return(specID).Twice()
   838  				return svc
   839  			},
   840  			FetchRequestServiceFn: func() *automock.FetchRequestService {
   841  				svc := &automock.FetchRequestService{}
   842  				svc.On("HandleSpec", ctx, fr).Return(nil)
   843  				return svc
   844  			},
   845  			ResourceType: resource.ApplicationTemplateVersion,
   846  			Input:        *specInputWithFR,
   847  			ExpectedErr:  testErr,
   848  		},
   849  	}
   850  
   851  	for _, testCase := range testCases {
   852  		t.Run(testCase.Name, func(t *testing.T) {
   853  			// GIVEN
   854  			repo := testCase.RepositoryFn()
   855  			fetchRequestRepo := testCase.FetchRequestRepoFn()
   856  			uidService := testCase.UIDServiceFn()
   857  			fetchRequestService := testCase.FetchRequestServiceFn()
   858  
   859  			svc := spec.NewService(repo, fetchRequestRepo, uidService, fetchRequestService)
   860  			svc.SetTimestampGen(func() time.Time {
   861  				return timestamp
   862  			})
   863  
   864  			// WHEN
   865  			result, err := svc.CreateByReferenceObjectID(ctx, testCase.Input, testCase.ResourceType, model.APISpecReference, apiID)
   866  
   867  			// then
   868  			if testCase.ExpectedErr != nil {
   869  				require.Error(t, err)
   870  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
   871  			} else {
   872  				assert.IsType(t, "string", result)
   873  			}
   874  
   875  			repo.AssertExpectations(t)
   876  			fetchRequestRepo.AssertExpectations(t)
   877  			uidService.AssertExpectations(t)
   878  		})
   879  	}
   880  	t.Run("Error when tenant not in context", func(t *testing.T) {
   881  		svc := spec.NewService(nil, nil, fixUIDService(), nil)
   882  		// WHEN
   883  		_, err := svc.CreateByReferenceObjectID(context.TODO(), *fixModelAPISpecInput(), resource.Application, model.APISpecReference, apiID)
   884  		// THEN
   885  		require.Error(t, err)
   886  		assert.Contains(t, err.Error(), "cannot read tenant from context")
   887  	})
   888  }
   889  
   890  func TestService_CreateByReferenceObjectIDWithDelayedFetchRequest(t *testing.T) {
   891  	// GIVEN
   892  	testErr := errors.New("Test error")
   893  
   894  	ctx := context.TODO()
   895  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
   896  
   897  	specInputWithFR := fixModelAPISpecInputWithFetchRequest()
   898  	specInputWithFR.Data = nil
   899  
   900  	specInputWithEmptyAPIType := fixModelAPISpecInputWithFetchRequest()
   901  	specInputWithEmptyAPIType.APIType = nil
   902  
   903  	specModel := fixModelAPISpec()
   904  	specModel.Data = nil
   905  
   906  	timestamp := time.Now()
   907  
   908  	fr := &model.FetchRequest{
   909  		ID:   specID,
   910  		URL:  "foo.bar",
   911  		Mode: model.FetchModeSingle,
   912  		Status: &model.FetchRequestStatus{
   913  			Condition: model.FetchRequestStatusConditionInitial,
   914  			Timestamp: timestamp,
   915  		},
   916  		ObjectType: model.APISpecFetchRequestReference,
   917  		ObjectID:   specID,
   918  	}
   919  
   920  	testCases := []struct {
   921  		Name               string
   922  		RepositoryFn       func() *automock.SpecRepository
   923  		FetchRequestRepoFn func() *automock.FetchRequestRepository
   924  		UIDServiceFn       func() *automock.UIDService
   925  		Input              model.SpecInput
   926  		ResourceType       resource.Type
   927  		ExpectedErr        error
   928  	}{
   929  		{
   930  			Name: "Success for Application",
   931  			RepositoryFn: func() *automock.SpecRepository {
   932  				repo := &automock.SpecRepository{}
   933  				repo.On("Create", ctx, tenant, specModel).Return(nil).Once()
   934  
   935  				return repo
   936  			},
   937  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   938  				repo := &automock.FetchRequestRepository{}
   939  				repo.On("Create", ctx, tenant, fr).Return(nil).Once()
   940  
   941  				return repo
   942  			},
   943  			UIDServiceFn: func() *automock.UIDService {
   944  				svc := &automock.UIDService{}
   945  				svc.On("Generate").Return(specID).Twice()
   946  				return svc
   947  			},
   948  			Input:        *specInputWithFR,
   949  			ResourceType: resource.Application,
   950  			ExpectedErr:  nil,
   951  		},
   952  		{
   953  			Name: "Success for Application Template Version",
   954  			RepositoryFn: func() *automock.SpecRepository {
   955  				repo := &automock.SpecRepository{}
   956  				repo.On("CreateGlobal", ctx, specModel).Return(nil).Once()
   957  
   958  				return repo
   959  			},
   960  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   961  				repo := &automock.FetchRequestRepository{}
   962  				repo.On("CreateGlobal", ctx, fr).Return(nil).Once()
   963  
   964  				return repo
   965  			},
   966  			UIDServiceFn: func() *automock.UIDService {
   967  				svc := &automock.UIDService{}
   968  				svc.On("Generate").Return(specID).Twice()
   969  				return svc
   970  			},
   971  			Input:        *specInputWithFR,
   972  			ResourceType: resource.ApplicationTemplateVersion,
   973  			ExpectedErr:  nil,
   974  		},
   975  		{
   976  			Name: "Error - spec conversion",
   977  			RepositoryFn: func() *automock.SpecRepository {
   978  				return &automock.SpecRepository{}
   979  			},
   980  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
   981  				return &automock.FetchRequestRepository{}
   982  			},
   983  			UIDServiceFn: func() *automock.UIDService {
   984  				svc := &automock.UIDService{}
   985  				svc.On("Generate").Return(specID).Once()
   986  				return svc
   987  			},
   988  			Input:        *specInputWithEmptyAPIType,
   989  			ResourceType: resource.Application,
   990  			ExpectedErr:  errors.New("API Spec type cannot be empty"),
   991  		},
   992  		{
   993  			Name: "Error - Spec Creation for Application",
   994  			RepositoryFn: func() *automock.SpecRepository {
   995  				repo := &automock.SpecRepository{}
   996  				repo.On("Create", ctx, tenant, specModel).Return(testErr).Once()
   997  				return repo
   998  			},
   999  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1000  				return &automock.FetchRequestRepository{}
  1001  			},
  1002  			UIDServiceFn: func() *automock.UIDService {
  1003  				svc := &automock.UIDService{}
  1004  				svc.On("Generate").Return(specID).Once()
  1005  				return svc
  1006  			},
  1007  			Input:        *specInputWithFR,
  1008  			ResourceType: resource.Application,
  1009  			ExpectedErr:  testErr,
  1010  		},
  1011  		{
  1012  			Name: "Error - Spec Creation for Application Template Version",
  1013  			RepositoryFn: func() *automock.SpecRepository {
  1014  				repo := &automock.SpecRepository{}
  1015  				repo.On("CreateGlobal", ctx, specModel).Return(testErr).Once()
  1016  				return repo
  1017  			},
  1018  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1019  				return &automock.FetchRequestRepository{}
  1020  			},
  1021  			UIDServiceFn: func() *automock.UIDService {
  1022  				svc := &automock.UIDService{}
  1023  				svc.On("Generate").Return(specID).Once()
  1024  				return svc
  1025  			},
  1026  			Input:        *specInputWithFR,
  1027  			ResourceType: resource.ApplicationTemplateVersion,
  1028  			ExpectedErr:  testErr,
  1029  		},
  1030  		{
  1031  			Name: "Error - Fetch Request Creation for Application",
  1032  			RepositoryFn: func() *automock.SpecRepository {
  1033  				repo := &automock.SpecRepository{}
  1034  				repo.On("Create", ctx, tenant, specModel).Return(nil).Once()
  1035  				return repo
  1036  			},
  1037  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1038  				repo := &automock.FetchRequestRepository{}
  1039  				repo.On("Create", ctx, tenant, fr).Return(testErr).Once()
  1040  				return repo
  1041  			},
  1042  			UIDServiceFn: func() *automock.UIDService {
  1043  				svc := &automock.UIDService{}
  1044  				svc.On("Generate").Return(specID).Twice()
  1045  				return svc
  1046  			},
  1047  			Input:        *specInputWithFR,
  1048  			ResourceType: resource.Application,
  1049  			ExpectedErr:  testErr,
  1050  		},
  1051  		{
  1052  			Name: "Error - Fetch Request Creation for Application Template Version",
  1053  			RepositoryFn: func() *automock.SpecRepository {
  1054  				repo := &automock.SpecRepository{}
  1055  				repo.On("CreateGlobal", ctx, specModel).Return(nil).Once()
  1056  				return repo
  1057  			},
  1058  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1059  				repo := &automock.FetchRequestRepository{}
  1060  				repo.On("CreateGlobal", ctx, fr).Return(testErr).Once()
  1061  				return repo
  1062  			},
  1063  			UIDServiceFn: func() *automock.UIDService {
  1064  				svc := &automock.UIDService{}
  1065  				svc.On("Generate").Return(specID).Twice()
  1066  				return svc
  1067  			},
  1068  			Input:        *specInputWithFR,
  1069  			ResourceType: resource.ApplicationTemplateVersion,
  1070  			ExpectedErr:  testErr,
  1071  		},
  1072  	}
  1073  
  1074  	for _, testCase := range testCases {
  1075  		t.Run(testCase.Name, func(t *testing.T) {
  1076  			// GIVEN
  1077  			repo := testCase.RepositoryFn()
  1078  			fetchRequestRepo := testCase.FetchRequestRepoFn()
  1079  			uidService := testCase.UIDServiceFn()
  1080  
  1081  			svc := spec.NewService(repo, fetchRequestRepo, uidService, nil)
  1082  			svc.SetTimestampGen(func() time.Time {
  1083  				return timestamp
  1084  			})
  1085  
  1086  			// WHEN
  1087  			result, fr, err := svc.CreateByReferenceObjectIDWithDelayedFetchRequest(ctx, testCase.Input, testCase.ResourceType, model.APISpecReference, apiID)
  1088  
  1089  			// then
  1090  			if testCase.ExpectedErr != nil {
  1091  				require.Error(t, err)
  1092  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
  1093  			} else {
  1094  				assert.IsType(t, "string", result)
  1095  				assert.NotEmpty(t, fr)
  1096  			}
  1097  
  1098  			repo.AssertExpectations(t)
  1099  			fetchRequestRepo.AssertExpectations(t)
  1100  			uidService.AssertExpectations(t)
  1101  		})
  1102  	}
  1103  	t.Run("Error when tenant not in context", func(t *testing.T) {
  1104  		svc := spec.NewService(nil, nil, fixUIDService(), nil)
  1105  		// WHEN
  1106  		_, _, err := svc.CreateByReferenceObjectIDWithDelayedFetchRequest(context.TODO(), *fixModelAPISpecInput(), resource.Application, model.APISpecReference, apiID)
  1107  		// THEN
  1108  		require.Error(t, err)
  1109  		assert.Contains(t, err.Error(), "cannot read tenant from context")
  1110  	})
  1111  }
  1112  
  1113  func TestService_UpdateByReferenceObjectID(t *testing.T) {
  1114  	// GIVEN
  1115  	testErr := errors.New("Test error")
  1116  
  1117  	ctx := context.TODO()
  1118  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
  1119  
  1120  	specData := "specData"
  1121  
  1122  	specInputWithFR := fixModelAPISpecInputWithFetchRequest()
  1123  	specInputWithFR.Data = nil
  1124  
  1125  	specModel := fixModelAPISpec()
  1126  	specModel.Data = nil
  1127  
  1128  	timestamp := time.Now()
  1129  
  1130  	fr := &model.FetchRequest{
  1131  		ID:   specID,
  1132  		URL:  "foo.bar",
  1133  		Mode: model.FetchModeSingle,
  1134  		Status: &model.FetchRequestStatus{
  1135  			Condition: model.FetchRequestStatusConditionInitial,
  1136  			Timestamp: timestamp,
  1137  		},
  1138  		ObjectType: model.APISpecFetchRequestReference,
  1139  		ObjectID:   specID,
  1140  	}
  1141  
  1142  	testCases := []struct {
  1143  		Name                  string
  1144  		RepositoryFn          func() *automock.SpecRepository
  1145  		FetchRequestRepoFn    func() *automock.FetchRequestRepository
  1146  		UIDServiceFn          func() *automock.UIDService
  1147  		FetchRequestServiceFn func() *automock.FetchRequestService
  1148  		ResourceType          resource.Type
  1149  		Input                 model.SpecInput
  1150  		InputID               string
  1151  		ExpectedErr           error
  1152  	}{
  1153  		{
  1154  			Name: "Success for Application",
  1155  			RepositoryFn: func() *automock.SpecRepository {
  1156  				repo := &automock.SpecRepository{}
  1157  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(specModel, nil).Once()
  1158  				repo.On("Update", ctx, tenant, fixModelAPISpec()).Return(nil).Once()
  1159  				return repo
  1160  			},
  1161  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1162  				repo := &automock.FetchRequestRepository{}
  1163  				repo.On("DeleteByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil).Once()
  1164  				repo.On("Create", ctx, tenant, fr).Return(nil).Once()
  1165  
  1166  				return repo
  1167  			},
  1168  			UIDServiceFn: func() *automock.UIDService {
  1169  				svc := &automock.UIDService{}
  1170  				svc.On("Generate").Return(specID).Once()
  1171  				return svc
  1172  			},
  1173  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1174  				svc := &automock.FetchRequestService{}
  1175  				svc.On("HandleSpec", ctx, fr).Return(&specData)
  1176  				return svc
  1177  			},
  1178  			ResourceType: resource.Application,
  1179  			InputID:      specID,
  1180  			Input:        *specInputWithFR,
  1181  			ExpectedErr:  nil,
  1182  		},
  1183  		{
  1184  			Name: "Success for Application Template Version",
  1185  			RepositoryFn: func() *automock.SpecRepository {
  1186  				repo := &automock.SpecRepository{}
  1187  				repo.On("GetByIDGlobal", ctx, specID).Return(specModel, nil).Once()
  1188  				repo.On("UpdateGlobal", ctx, fixModelAPISpec()).Return(nil).Once()
  1189  				return repo
  1190  			},
  1191  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1192  				repo := &automock.FetchRequestRepository{}
  1193  				repo.On("DeleteByReferenceObjectIDGlobal", ctx, model.APISpecFetchRequestReference, specID).Return(nil).Once()
  1194  				repo.On("CreateGlobal", ctx, fr).Return(nil).Once()
  1195  
  1196  				return repo
  1197  			},
  1198  			UIDServiceFn: func() *automock.UIDService {
  1199  				svc := &automock.UIDService{}
  1200  				svc.On("Generate").Return(specID).Once()
  1201  				return svc
  1202  			},
  1203  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1204  				svc := &automock.FetchRequestService{}
  1205  				svc.On("HandleSpec", ctx, fr).Return(&specData)
  1206  				return svc
  1207  			},
  1208  			ResourceType: resource.ApplicationTemplateVersion,
  1209  			InputID:      specID,
  1210  			Input:        *specInputWithFR,
  1211  			ExpectedErr:  nil,
  1212  		},
  1213  		{
  1214  			Name: "Update Error For Application",
  1215  			RepositoryFn: func() *automock.SpecRepository {
  1216  				repo := &automock.SpecRepository{}
  1217  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(specModel, nil).Once()
  1218  				repo.On("Update", ctx, tenant, specModel).Return(testErr).Once()
  1219  				return repo
  1220  			},
  1221  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1222  				repo := &automock.FetchRequestRepository{}
  1223  				repo.On("DeleteByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil).Once()
  1224  				repo.On("Create", ctx, tenant, fr).Return(nil).Once()
  1225  
  1226  				return repo
  1227  			},
  1228  			UIDServiceFn: func() *automock.UIDService {
  1229  				svc := &automock.UIDService{}
  1230  				svc.On("Generate").Return(specID).Once()
  1231  				return svc
  1232  			},
  1233  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1234  				svc := &automock.FetchRequestService{}
  1235  				svc.On("HandleSpec", ctx, fr).Return(nil)
  1236  				return svc
  1237  			},
  1238  			ResourceType: resource.Application,
  1239  			InputID:      specID,
  1240  			Input:        *specInputWithFR,
  1241  			ExpectedErr:  testErr,
  1242  		},
  1243  		{
  1244  			Name: "Update Error For Application Template Version",
  1245  			RepositoryFn: func() *automock.SpecRepository {
  1246  				repo := &automock.SpecRepository{}
  1247  				repo.On("GetByIDGlobal", ctx, specID).Return(specModel, nil).Once()
  1248  				repo.On("UpdateGlobal", ctx, specModel).Return(testErr).Once()
  1249  				return repo
  1250  			},
  1251  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1252  				repo := &automock.FetchRequestRepository{}
  1253  				repo.On("DeleteByReferenceObjectIDGlobal", ctx, model.APISpecFetchRequestReference, specID).Return(nil).Once()
  1254  				repo.On("CreateGlobal", ctx, fr).Return(nil).Once()
  1255  
  1256  				return repo
  1257  			},
  1258  			UIDServiceFn: func() *automock.UIDService {
  1259  				svc := &automock.UIDService{}
  1260  				svc.On("Generate").Return(specID).Once()
  1261  				return svc
  1262  			},
  1263  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1264  				svc := &automock.FetchRequestService{}
  1265  				svc.On("HandleSpec", ctx, fr).Return(nil)
  1266  				return svc
  1267  			},
  1268  			ResourceType: resource.ApplicationTemplateVersion,
  1269  			InputID:      specID,
  1270  			Input:        *specInputWithFR,
  1271  			ExpectedErr:  testErr,
  1272  		},
  1273  		{
  1274  			Name: "Delete FetchRequest by reference Error for Application",
  1275  			RepositoryFn: func() *automock.SpecRepository {
  1276  				repo := &automock.SpecRepository{}
  1277  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(specModel, nil).Once()
  1278  				return repo
  1279  			},
  1280  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1281  				repo := &automock.FetchRequestRepository{}
  1282  				repo.On("DeleteByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(testErr).Once()
  1283  				return repo
  1284  			},
  1285  			UIDServiceFn: func() *automock.UIDService {
  1286  				svc := &automock.UIDService{}
  1287  				return svc
  1288  			},
  1289  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1290  				svc := &automock.FetchRequestService{}
  1291  				return svc
  1292  			},
  1293  			ResourceType: resource.Application,
  1294  			InputID:      specID,
  1295  			Input:        *specInputWithFR,
  1296  			ExpectedErr:  testErr,
  1297  		},
  1298  		{
  1299  			Name: "Delete FetchRequest by reference Error for Application Template Version",
  1300  			RepositoryFn: func() *automock.SpecRepository {
  1301  				repo := &automock.SpecRepository{}
  1302  				repo.On("GetByIDGlobal", ctx, specID).Return(specModel, nil).Once()
  1303  				return repo
  1304  			},
  1305  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1306  				repo := &automock.FetchRequestRepository{}
  1307  				repo.On("DeleteByReferenceObjectIDGlobal", ctx, model.APISpecFetchRequestReference, specID).Return(testErr).Once()
  1308  				return repo
  1309  			},
  1310  			UIDServiceFn: func() *automock.UIDService {
  1311  				svc := &automock.UIDService{}
  1312  				return svc
  1313  			},
  1314  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1315  				svc := &automock.FetchRequestService{}
  1316  				return svc
  1317  			},
  1318  			ResourceType: resource.ApplicationTemplateVersion,
  1319  			InputID:      specID,
  1320  			Input:        *specInputWithFR,
  1321  			ExpectedErr:  testErr,
  1322  		},
  1323  		{
  1324  			Name: "Fetch Request Creation Error for Application",
  1325  			RepositoryFn: func() *automock.SpecRepository {
  1326  				repo := &automock.SpecRepository{}
  1327  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(specModel, nil).Once()
  1328  				return repo
  1329  			},
  1330  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1331  				repo := &automock.FetchRequestRepository{}
  1332  				repo.On("DeleteByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil).Once()
  1333  				repo.On("Create", ctx, tenant, fr).Return(testErr).Once()
  1334  				return repo
  1335  			},
  1336  			UIDServiceFn: func() *automock.UIDService {
  1337  				svc := &automock.UIDService{}
  1338  				svc.On("Generate").Return(specID).Once()
  1339  				return svc
  1340  			},
  1341  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1342  				svc := &automock.FetchRequestService{}
  1343  				return svc
  1344  			},
  1345  			ResourceType: resource.Application,
  1346  			InputID:      specID,
  1347  			Input:        *specInputWithFR,
  1348  			ExpectedErr:  testErr,
  1349  		},
  1350  		{
  1351  			Name: "Fetch Request Creation Error for Application Template Version",
  1352  			RepositoryFn: func() *automock.SpecRepository {
  1353  				repo := &automock.SpecRepository{}
  1354  				repo.On("GetByIDGlobal", ctx, specID).Return(specModel, nil).Once()
  1355  				return repo
  1356  			},
  1357  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1358  				repo := &automock.FetchRequestRepository{}
  1359  				repo.On("DeleteByReferenceObjectIDGlobal", ctx, model.APISpecFetchRequestReference, specID).Return(nil).Once()
  1360  				repo.On("CreateGlobal", ctx, fr).Return(testErr).Once()
  1361  				return repo
  1362  			},
  1363  			UIDServiceFn: func() *automock.UIDService {
  1364  				svc := &automock.UIDService{}
  1365  				svc.On("Generate").Return(specID).Once()
  1366  				return svc
  1367  			},
  1368  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1369  				svc := &automock.FetchRequestService{}
  1370  				return svc
  1371  			},
  1372  			ResourceType: resource.ApplicationTemplateVersion,
  1373  			InputID:      specID,
  1374  			Input:        *specInputWithFR,
  1375  			ExpectedErr:  testErr,
  1376  		},
  1377  		{
  1378  			Name: "Get Error for Application",
  1379  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1380  				repo := &automock.FetchRequestRepository{}
  1381  				return repo
  1382  			},
  1383  			UIDServiceFn: func() *automock.UIDService {
  1384  				svc := &automock.UIDService{}
  1385  				return svc
  1386  			},
  1387  			RepositoryFn: func() *automock.SpecRepository {
  1388  				repo := &automock.SpecRepository{}
  1389  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(nil, testErr).Once()
  1390  				return repo
  1391  			},
  1392  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1393  				svc := &automock.FetchRequestService{}
  1394  				return svc
  1395  			},
  1396  			ResourceType: resource.Application,
  1397  			InputID:      specID,
  1398  			Input:        *specInputWithFR,
  1399  			ExpectedErr:  testErr,
  1400  		},
  1401  		{
  1402  			Name: "Get Error for Application Template Version",
  1403  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1404  				repo := &automock.FetchRequestRepository{}
  1405  				return repo
  1406  			},
  1407  			UIDServiceFn: func() *automock.UIDService {
  1408  				svc := &automock.UIDService{}
  1409  				return svc
  1410  			},
  1411  			RepositoryFn: func() *automock.SpecRepository {
  1412  				repo := &automock.SpecRepository{}
  1413  				repo.On("GetByIDGlobal", ctx, specID).Return(nil, testErr).Once()
  1414  				return repo
  1415  			},
  1416  			FetchRequestServiceFn: func() *automock.FetchRequestService {
  1417  				svc := &automock.FetchRequestService{}
  1418  				return svc
  1419  			},
  1420  			ResourceType: resource.ApplicationTemplateVersion,
  1421  			InputID:      specID,
  1422  			Input:        *specInputWithFR,
  1423  			ExpectedErr:  testErr,
  1424  		},
  1425  	}
  1426  
  1427  	for _, testCase := range testCases {
  1428  		t.Run(testCase.Name, func(t *testing.T) {
  1429  			// GIVEN
  1430  			repo := testCase.RepositoryFn()
  1431  			fetchRequestRepo := testCase.FetchRequestRepoFn()
  1432  			uidSvc := testCase.UIDServiceFn()
  1433  			fetchRequestSvc := testCase.FetchRequestServiceFn()
  1434  
  1435  			svc := spec.NewService(repo, fetchRequestRepo, uidSvc, fetchRequestSvc)
  1436  			svc.SetTimestampGen(func() time.Time { return timestamp })
  1437  
  1438  			// WHEN
  1439  			err := svc.UpdateByReferenceObjectID(ctx, testCase.InputID, testCase.Input, testCase.ResourceType, model.APISpecReference, apiID)
  1440  
  1441  			// then
  1442  			if testCase.ExpectedErr == nil {
  1443  				require.NoError(t, err)
  1444  			} else {
  1445  				require.Error(t, err)
  1446  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
  1447  			}
  1448  
  1449  			repo.AssertExpectations(t)
  1450  			fetchRequestRepo.AssertExpectations(t)
  1451  			uidSvc.AssertExpectations(t)
  1452  		})
  1453  	}
  1454  	t.Run("Error when tenant not in context", func(t *testing.T) {
  1455  		svc := spec.NewService(nil, nil, nil, nil)
  1456  		// WHEN
  1457  		err := svc.UpdateByReferenceObjectID(context.TODO(), "", model.SpecInput{}, resource.Application, model.APISpecReference, apiID)
  1458  		// THEN
  1459  		require.Error(t, err)
  1460  		assert.Contains(t, err.Error(), "cannot read tenant from context")
  1461  	})
  1462  }
  1463  
  1464  func TestService_UpdateSpecOnly(t *testing.T) {
  1465  	testSpec := &model.Spec{}
  1466  
  1467  	testCases := []struct {
  1468  		Name           string
  1469  		Context        context.Context
  1470  		SpecRepoMock   *automock.SpecRepository
  1471  		ExpectedResult *model.Spec
  1472  		ExpectedError  error
  1473  	}{
  1474  		{
  1475  			Name:    "Success",
  1476  			Context: tnt.SaveToContext(context.TODO(), tenantID, tenantID),
  1477  			SpecRepoMock: func() *automock.SpecRepository {
  1478  				specRepositoryMock := automock.SpecRepository{}
  1479  				specRepositoryMock.On("Update", mock.Anything, tenantID, testSpec).Return(nil).Once()
  1480  				return &specRepositoryMock
  1481  			}(),
  1482  			ExpectedError: nil,
  1483  		},
  1484  		{
  1485  			Name:          "Fails when tenant is missing in context",
  1486  			Context:       context.TODO(),
  1487  			SpecRepoMock:  &automock.SpecRepository{},
  1488  			ExpectedError: apperrors.NewCannotReadTenantError(),
  1489  		},
  1490  		{
  1491  			Name:    "Fails when repo update fails",
  1492  			Context: tnt.SaveToContext(context.TODO(), tenantID, tenantID),
  1493  			SpecRepoMock: func() *automock.SpecRepository {
  1494  				specRepositoryMock := automock.SpecRepository{}
  1495  				specRepositoryMock.On("Update", mock.Anything, tenantID, testSpec).Return(testErr).Once()
  1496  				return &specRepositoryMock
  1497  			}(),
  1498  			ExpectedError: testErr,
  1499  		},
  1500  	}
  1501  
  1502  	for _, testCase := range testCases {
  1503  		t.Run(testCase.Name, func(t *testing.T) {
  1504  			repo := testCase.SpecRepoMock
  1505  			svc := spec.NewService(repo, nil, nil, nil)
  1506  
  1507  			err := svc.UpdateSpecOnly(testCase.Context, *testSpec)
  1508  			if testCase.ExpectedError != nil {
  1509  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1510  			}
  1511  
  1512  			repo.AssertExpectations(t)
  1513  		})
  1514  	}
  1515  }
  1516  
  1517  func TestService_UpdateSpecOnlyGlobal(t *testing.T) {
  1518  	testSpec := &model.Spec{}
  1519  
  1520  	testCases := []struct {
  1521  		Name           string
  1522  		SpecRepoMock   *automock.SpecRepository
  1523  		ExpectedResult *model.Spec
  1524  		ExpectedError  error
  1525  	}{
  1526  		{
  1527  			Name: "Success",
  1528  			SpecRepoMock: func() *automock.SpecRepository {
  1529  				specRepositoryMock := automock.SpecRepository{}
  1530  				specRepositoryMock.On("UpdateGlobal", mock.Anything, testSpec).Return(nil).Once()
  1531  				return &specRepositoryMock
  1532  			}(),
  1533  			ExpectedError: nil,
  1534  		},
  1535  		{
  1536  			Name: "Fails when repo update fails",
  1537  			SpecRepoMock: func() *automock.SpecRepository {
  1538  				specRepositoryMock := automock.SpecRepository{}
  1539  				specRepositoryMock.On("UpdateGlobal", mock.Anything, testSpec).Return(testErr).Once()
  1540  				return &specRepositoryMock
  1541  			}(),
  1542  			ExpectedError: testErr,
  1543  		},
  1544  	}
  1545  
  1546  	for _, testCase := range testCases {
  1547  		t.Run(testCase.Name, func(t *testing.T) {
  1548  			repo := testCase.SpecRepoMock
  1549  			svc := spec.NewService(repo, nil, nil, nil)
  1550  
  1551  			err := svc.UpdateSpecOnlyGlobal(context.TODO(), *testSpec)
  1552  			if testCase.ExpectedError != nil {
  1553  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
  1554  			}
  1555  
  1556  			repo.AssertExpectations(t)
  1557  		})
  1558  	}
  1559  }
  1560  
  1561  func TestService_Delete(t *testing.T) {
  1562  	// GIVEN
  1563  	testErr := errors.New("Test error")
  1564  
  1565  	id := "foo"
  1566  
  1567  	ctx := context.TODO()
  1568  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
  1569  
  1570  	var testCases = []struct {
  1571  		Name         string
  1572  		RepositoryFn func() *automock.SpecRepository
  1573  		InputID      string
  1574  		ExpectedErr  error
  1575  	}{
  1576  		{
  1577  			Name: "Success",
  1578  			RepositoryFn: func() *automock.SpecRepository {
  1579  				repo := &automock.SpecRepository{}
  1580  				repo.On("Delete", ctx, tenant, id, model.APISpecReference).Return(nil).Once()
  1581  				return repo
  1582  			},
  1583  			InputID:     id,
  1584  			ExpectedErr: nil,
  1585  		},
  1586  		{
  1587  			Name: "Delete Error",
  1588  			RepositoryFn: func() *automock.SpecRepository {
  1589  				repo := &automock.SpecRepository{}
  1590  				repo.On("Delete", ctx, tenant, id, model.APISpecReference).Return(testErr).Once()
  1591  				return repo
  1592  			},
  1593  			InputID:     id,
  1594  			ExpectedErr: testErr,
  1595  		},
  1596  	}
  1597  	for _, testCase := range testCases {
  1598  		t.Run(testCase.Name, func(t *testing.T) {
  1599  			// GIVEN
  1600  			repo := testCase.RepositoryFn()
  1601  
  1602  			svc := spec.NewService(repo, nil, nil, nil)
  1603  
  1604  			// WHEN
  1605  			err := svc.Delete(ctx, testCase.InputID, model.APISpecReference)
  1606  
  1607  			// then
  1608  			if testCase.ExpectedErr == nil {
  1609  				require.NoError(t, err)
  1610  			} else {
  1611  				require.Error(t, err)
  1612  				assert.Contains(t, err.Error(), testCase.ExpectedErr.Error())
  1613  			}
  1614  
  1615  			repo.AssertExpectations(t)
  1616  		})
  1617  	}
  1618  
  1619  	t.Run("Error when tenant not in context", func(t *testing.T) {
  1620  		svc := spec.NewService(nil, nil, nil, nil)
  1621  		// WHEN
  1622  		err := svc.Delete(context.TODO(), "", model.APISpecReference)
  1623  		// THEN
  1624  		require.Error(t, err)
  1625  		assert.Contains(t, err.Error(), "cannot read tenant from context")
  1626  	})
  1627  }
  1628  
  1629  func TestService_RefetchSpec(t *testing.T) {
  1630  	// GIVEN
  1631  	testErr := errors.New("Test error")
  1632  
  1633  	ctx := context.TODO()
  1634  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
  1635  
  1636  	dataBytes := "data"
  1637  	modelSpec := &model.Spec{
  1638  		Data: &dataBytes,
  1639  	}
  1640  
  1641  	timestamp := time.Now()
  1642  	fr := &model.FetchRequest{
  1643  		Status: &model.FetchRequestStatus{
  1644  			Condition: model.FetchRequestStatusConditionInitial,
  1645  			Timestamp: timestamp,
  1646  		},
  1647  	}
  1648  
  1649  	testCases := []struct {
  1650  		Name               string
  1651  		RepositoryFn       func() *automock.SpecRepository
  1652  		FetchRequestRepoFn func() *automock.FetchRequestRepository
  1653  		FetchRequestSvcFn  func() *automock.FetchRequestService
  1654  		ExpectedAPISpec    *model.Spec
  1655  		ExpectedErr        error
  1656  	}{
  1657  		{
  1658  			Name: "Success",
  1659  			RepositoryFn: func() *automock.SpecRepository {
  1660  				repo := &automock.SpecRepository{}
  1661  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(modelSpec, nil).Once()
  1662  				repo.On("Update", ctx, tenant, modelSpec).Return(nil).Once()
  1663  				return repo
  1664  			},
  1665  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1666  				repo := &automock.FetchRequestRepository{}
  1667  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil, nil)
  1668  				return repo
  1669  			},
  1670  			FetchRequestSvcFn: func() *automock.FetchRequestService {
  1671  				return &automock.FetchRequestService{}
  1672  			},
  1673  			ExpectedAPISpec: modelSpec,
  1674  			ExpectedErr:     nil,
  1675  		},
  1676  		{
  1677  			Name: "Success - fetched API Spec",
  1678  			RepositoryFn: func() *automock.SpecRepository {
  1679  				repo := &automock.SpecRepository{}
  1680  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(modelSpec, nil).Once()
  1681  				repo.On("Update", ctx, tenant, modelSpec).Return(nil).Once()
  1682  				return repo
  1683  			},
  1684  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1685  				repo := &automock.FetchRequestRepository{}
  1686  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(fr, nil)
  1687  				return repo
  1688  			},
  1689  			FetchRequestSvcFn: func() *automock.FetchRequestService {
  1690  				svc := &automock.FetchRequestService{}
  1691  				svc.On("HandleSpec", ctx, fr).Return(&dataBytes)
  1692  				return svc
  1693  			},
  1694  			ExpectedAPISpec: modelSpec,
  1695  			ExpectedErr:     nil,
  1696  		},
  1697  		{
  1698  			Name: "Get from repository error",
  1699  			RepositoryFn: func() *automock.SpecRepository {
  1700  				repo := &automock.SpecRepository{}
  1701  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(nil, testErr).Once()
  1702  				return repo
  1703  			},
  1704  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1705  				return &automock.FetchRequestRepository{}
  1706  			},
  1707  			FetchRequestSvcFn: func() *automock.FetchRequestService {
  1708  				return &automock.FetchRequestService{}
  1709  			},
  1710  			ExpectedAPISpec: nil,
  1711  			ExpectedErr:     testErr,
  1712  		},
  1713  		{
  1714  			Name: "Get fetch request error",
  1715  			RepositoryFn: func() *automock.SpecRepository {
  1716  				repo := &automock.SpecRepository{}
  1717  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(modelSpec, nil).Once()
  1718  				return repo
  1719  			},
  1720  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1721  				repo := &automock.FetchRequestRepository{}
  1722  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil, testErr)
  1723  				return repo
  1724  			},
  1725  			FetchRequestSvcFn: func() *automock.FetchRequestService {
  1726  				return &automock.FetchRequestService{}
  1727  			},
  1728  			ExpectedAPISpec: nil,
  1729  			ExpectedErr:     errors.Wrapf(testErr, "while getting FetchRequest for Specification with id %q", specID),
  1730  		},
  1731  		{
  1732  			Name: "Error when updating API Definition failed",
  1733  			RepositoryFn: func() *automock.SpecRepository {
  1734  				repo := &automock.SpecRepository{}
  1735  				repo.On("GetByID", ctx, tenant, specID, model.APISpecReference).Return(modelSpec, nil).Once()
  1736  				repo.On("Update", ctx, tenant, modelSpec).Return(testErr).Once()
  1737  				return repo
  1738  			},
  1739  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1740  				repo := &automock.FetchRequestRepository{}
  1741  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil, nil)
  1742  				return repo
  1743  			},
  1744  			FetchRequestSvcFn: func() *automock.FetchRequestService {
  1745  				svc := &automock.FetchRequestService{}
  1746  				return svc
  1747  			},
  1748  			ExpectedAPISpec: nil,
  1749  			ExpectedErr:     errors.Wrapf(testErr, "while updating Specification with id %q", specID),
  1750  		},
  1751  	}
  1752  
  1753  	for _, testCase := range testCases {
  1754  		t.Run(testCase.Name, func(t *testing.T) {
  1755  			// GIVEN
  1756  			repo := testCase.RepositoryFn()
  1757  			frRepo := testCase.FetchRequestRepoFn()
  1758  			frSvc := testCase.FetchRequestSvcFn()
  1759  
  1760  			svc := spec.NewService(repo, frRepo, nil, frSvc)
  1761  
  1762  			// WHEN
  1763  			result, err := svc.RefetchSpec(ctx, specID, model.APISpecReference)
  1764  
  1765  			// then
  1766  			assert.Equal(t, testCase.ExpectedAPISpec, result)
  1767  
  1768  			if testCase.ExpectedErr != nil {
  1769  				require.Error(t, err)
  1770  				assert.Equal(t, testCase.ExpectedErr.Error(), err.Error())
  1771  			} else {
  1772  				assert.NoError(t, err)
  1773  			}
  1774  			repo.AssertExpectations(t)
  1775  		})
  1776  	}
  1777  	t.Run("Error when tenant not in context", func(t *testing.T) {
  1778  		svc := spec.NewService(nil, nil, nil, nil)
  1779  		// WHEN
  1780  		_, err := svc.RefetchSpec(context.TODO(), "", model.APISpecReference)
  1781  		// THEN
  1782  		require.Error(t, err)
  1783  		assert.Contains(t, err.Error(), "cannot read tenant from context")
  1784  	})
  1785  }
  1786  
  1787  func TestService_GetFetchRequest(t *testing.T) {
  1788  	// GIVEN
  1789  	ctx := context.TODO()
  1790  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
  1791  
  1792  	testErr := errors.New("Test error")
  1793  
  1794  	frURL := "foo.bar"
  1795  
  1796  	timestamp := time.Now()
  1797  	fr := &model.FetchRequest{
  1798  		URL: frURL,
  1799  		Status: &model.FetchRequestStatus{
  1800  			Condition: model.FetchRequestStatusConditionInitial,
  1801  			Timestamp: timestamp,
  1802  		},
  1803  	}
  1804  
  1805  	testCases := []struct {
  1806  		Name                 string
  1807  		RepositoryFn         func() *automock.SpecRepository
  1808  		FetchRequestRepoFn   func() *automock.FetchRequestRepository
  1809  		InputAPIDefID        string
  1810  		ExpectedFetchRequest *model.FetchRequest
  1811  		ExpectedErrMessage   string
  1812  	}{
  1813  		{
  1814  			Name: "Success",
  1815  			RepositoryFn: func() *automock.SpecRepository {
  1816  				repo := &automock.SpecRepository{}
  1817  				repo.On("Exists", ctx, tenant, specID, model.APISpecReference).Return(true, nil).Once()
  1818  				return repo
  1819  			},
  1820  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1821  				repo := &automock.FetchRequestRepository{}
  1822  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(fr, nil).Once()
  1823  				return repo
  1824  			},
  1825  			InputAPIDefID:        specID,
  1826  			ExpectedFetchRequest: fr,
  1827  			ExpectedErrMessage:   "",
  1828  		},
  1829  		{
  1830  			Name: "Error - Spec Not Exist",
  1831  			RepositoryFn: func() *automock.SpecRepository {
  1832  				repo := &automock.SpecRepository{}
  1833  				repo.On("Exists", ctx, tenant, specID, model.APISpecReference).Return(false, nil).Once()
  1834  				return repo
  1835  			},
  1836  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1837  				return &automock.FetchRequestRepository{}
  1838  			},
  1839  			InputAPIDefID:        specID,
  1840  			ExpectedFetchRequest: nil,
  1841  			ExpectedErrMessage:   fmt.Sprintf("specification with id %q doesn't exist", specID),
  1842  		},
  1843  		{
  1844  			Name: "Success - Not Found",
  1845  			RepositoryFn: func() *automock.SpecRepository {
  1846  				repo := &automock.SpecRepository{}
  1847  				repo.On("Exists", ctx, tenant, specID, model.APISpecReference).Return(true, nil).Once()
  1848  				return repo
  1849  			},
  1850  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1851  				repo := &automock.FetchRequestRepository{}
  1852  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil, apperrors.NewNotFoundError(resource.API, "")).Once()
  1853  				return repo
  1854  			},
  1855  			InputAPIDefID:        specID,
  1856  			ExpectedFetchRequest: nil,
  1857  			ExpectedErrMessage:   fmt.Sprintf("while getting FetchRequest by Specification with id %q", specID),
  1858  		},
  1859  		{
  1860  			Name: "Error - Get FetchRequest",
  1861  			RepositoryFn: func() *automock.SpecRepository {
  1862  				repo := &automock.SpecRepository{}
  1863  				repo.On("Exists", ctx, tenant, specID, model.APISpecReference).Return(true, nil).Once()
  1864  				return repo
  1865  			},
  1866  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1867  				repo := &automock.FetchRequestRepository{}
  1868  				repo.On("GetByReferenceObjectID", ctx, tenant, model.APISpecFetchRequestReference, specID).Return(nil, testErr).Once()
  1869  				return repo
  1870  			},
  1871  			InputAPIDefID:        specID,
  1872  			ExpectedFetchRequest: nil,
  1873  			ExpectedErrMessage:   testErr.Error(),
  1874  		},
  1875  		{
  1876  			Name: "Error - Spec doesn't exist",
  1877  			RepositoryFn: func() *automock.SpecRepository {
  1878  				repo := &automock.SpecRepository{}
  1879  				repo.On("Exists", ctx, tenant, specID, model.APISpecReference).Return(false, testErr).Once()
  1880  
  1881  				return repo
  1882  			},
  1883  			FetchRequestRepoFn: func() *automock.FetchRequestRepository {
  1884  				repo := &automock.FetchRequestRepository{}
  1885  				return repo
  1886  			},
  1887  			InputAPIDefID:      specID,
  1888  			ExpectedErrMessage: testErr.Error(),
  1889  		},
  1890  	}
  1891  
  1892  	for _, testCase := range testCases {
  1893  		t.Run(testCase.Name, func(t *testing.T) {
  1894  			repo := testCase.RepositoryFn()
  1895  			fetchRequestRepo := testCase.FetchRequestRepoFn()
  1896  			svc := spec.NewService(repo, fetchRequestRepo, nil, nil)
  1897  
  1898  			// WHEN
  1899  			l, err := svc.GetFetchRequest(ctx, testCase.InputAPIDefID, model.APISpecReference)
  1900  
  1901  			// then
  1902  			if testCase.ExpectedErrMessage == "" {
  1903  				require.NoError(t, err)
  1904  				assert.Equal(t, l, testCase.ExpectedFetchRequest)
  1905  			} else {
  1906  				require.Error(t, err)
  1907  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  1908  			}
  1909  
  1910  			repo.AssertExpectations(t)
  1911  			fetchRequestRepo.AssertExpectations(t)
  1912  		})
  1913  	}
  1914  	t.Run("Returns error on loading tenant", func(t *testing.T) {
  1915  		svc := spec.NewService(nil, nil, nil, nil)
  1916  		// WHEN
  1917  		_, err := svc.GetFetchRequest(context.TODO(), "dd", model.APISpecReference)
  1918  		assert.True(t, apperrors.IsCannotReadTenant(err))
  1919  	})
  1920  }
  1921  
  1922  func TestService_ListFetchRequestsByReferenceObjectIDs(t *testing.T) {
  1923  	// GIVEN
  1924  	testErr := errors.New("Test error")
  1925  	frURL := "foo.bar"
  1926  	firstFRID := "frID"
  1927  	secondFRID := "frID2"
  1928  	firstSpecID := "specID"
  1929  	secondSpecID := "specID2"
  1930  	specIDs := []string{firstSpecID, secondSpecID}
  1931  	timestamp := time.Now()
  1932  
  1933  	firstFetchRequest := &model.FetchRequest{
  1934  		ID:  firstFRID,
  1935  		URL: frURL,
  1936  		Status: &model.FetchRequestStatus{
  1937  			Condition: model.FetchRequestStatusConditionInitial,
  1938  			Timestamp: timestamp,
  1939  		},
  1940  	}
  1941  
  1942  	secondFetchRequest := &model.FetchRequest{
  1943  		ID:  secondFRID,
  1944  		URL: frURL,
  1945  		Status: &model.FetchRequestStatus{
  1946  			Condition: model.FetchRequestStatusConditionInitial,
  1947  			Timestamp: timestamp,
  1948  		},
  1949  	}
  1950  	fetchRequests := []*model.FetchRequest{firstFetchRequest, secondFetchRequest}
  1951  
  1952  	ctx := context.TODO()
  1953  	ctx = tnt.SaveToContext(ctx, tenant, externalTenant)
  1954  
  1955  	testCases := []struct {
  1956  		Name               string
  1957  		RepositoryFn       func() *automock.FetchRequestRepository
  1958  		ExpectedResult     []*model.FetchRequest
  1959  		ExpectedErrMessage string
  1960  	}{
  1961  		{
  1962  			Name: "Success",
  1963  			RepositoryFn: func() *automock.FetchRequestRepository {
  1964  				repo := &automock.FetchRequestRepository{}
  1965  				repo.On("ListByReferenceObjectIDs", ctx, tenant, model.APISpecFetchRequestReference, specIDs).Return(fetchRequests, nil).Once()
  1966  				return repo
  1967  			},
  1968  			ExpectedResult: fetchRequests,
  1969  		},
  1970  		{
  1971  			Name: "Returns error when Fetch Requests listing failed",
  1972  			RepositoryFn: func() *automock.FetchRequestRepository {
  1973  				repo := &automock.FetchRequestRepository{}
  1974  				repo.On("ListByReferenceObjectIDs", ctx, tenant, model.APISpecFetchRequestReference, specIDs).Return(nil, testErr).Once()
  1975  				return repo
  1976  			},
  1977  			ExpectedResult:     nil,
  1978  			ExpectedErrMessage: testErr.Error(),
  1979  		},
  1980  	}
  1981  
  1982  	for _, testCase := range testCases {
  1983  		t.Run(testCase.Name, func(t *testing.T) {
  1984  			repo := testCase.RepositoryFn()
  1985  
  1986  			svc := spec.NewService(nil, repo, nil, nil)
  1987  
  1988  			// WHEN
  1989  			frs, err := svc.ListFetchRequestsByReferenceObjectIDs(ctx, tenant, specIDs, model.APISpecReference)
  1990  
  1991  			// then
  1992  			if testCase.ExpectedErrMessage == "" {
  1993  				require.NoError(t, err)
  1994  				assert.Equal(t, testCase.ExpectedResult, frs)
  1995  			} else {
  1996  				require.Error(t, err)
  1997  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  1998  			}
  1999  
  2000  			repo.AssertExpectations(t)
  2001  		})
  2002  	}
  2003  }
  2004  
  2005  func TestService_ListFetchRequestsByReferenceObjectIDsGlobal(t *testing.T) {
  2006  	// GIVEN
  2007  	testErr := errors.New("Test error")
  2008  	frURL := "foo.bar"
  2009  	firstFRID := "frID"
  2010  	secondFRID := "frID2"
  2011  	firstSpecID := "specID"
  2012  	secondSpecID := "specID2"
  2013  	specIDs := []string{firstSpecID, secondSpecID}
  2014  	timestamp := time.Now()
  2015  
  2016  	firstFetchRequest := &model.FetchRequest{
  2017  		ID:  firstFRID,
  2018  		URL: frURL,
  2019  		Status: &model.FetchRequestStatus{
  2020  			Condition: model.FetchRequestStatusConditionInitial,
  2021  			Timestamp: timestamp,
  2022  		},
  2023  	}
  2024  
  2025  	secondFetchRequest := &model.FetchRequest{
  2026  		ID:  secondFRID,
  2027  		URL: frURL,
  2028  		Status: &model.FetchRequestStatus{
  2029  			Condition: model.FetchRequestStatusConditionInitial,
  2030  			Timestamp: timestamp,
  2031  		},
  2032  	}
  2033  	fetchRequests := []*model.FetchRequest{firstFetchRequest, secondFetchRequest}
  2034  
  2035  	ctx := context.TODO()
  2036  
  2037  	testCases := []struct {
  2038  		Name               string
  2039  		RepositoryFn       func() *automock.FetchRequestRepository
  2040  		ExpectedResult     []*model.FetchRequest
  2041  		ExpectedErrMessage string
  2042  	}{
  2043  		{
  2044  			Name: "Success",
  2045  			RepositoryFn: func() *automock.FetchRequestRepository {
  2046  				repo := &automock.FetchRequestRepository{}
  2047  				repo.On("ListByReferenceObjectIDsGlobal", ctx, model.APISpecFetchRequestReference, specIDs).Return(fetchRequests, nil).Once()
  2048  				return repo
  2049  			},
  2050  			ExpectedResult: fetchRequests,
  2051  		},
  2052  		{
  2053  			Name: "Returns error when Fetch Requests listing failed",
  2054  			RepositoryFn: func() *automock.FetchRequestRepository {
  2055  				repo := &automock.FetchRequestRepository{}
  2056  				repo.On("ListByReferenceObjectIDsGlobal", ctx, model.APISpecFetchRequestReference, specIDs).Return(nil, testErr).Once()
  2057  				return repo
  2058  			},
  2059  			ExpectedResult:     nil,
  2060  			ExpectedErrMessage: testErr.Error(),
  2061  		},
  2062  	}
  2063  
  2064  	for _, testCase := range testCases {
  2065  		t.Run(testCase.Name, func(t *testing.T) {
  2066  			repo := testCase.RepositoryFn()
  2067  
  2068  			svc := spec.NewService(nil, repo, nil, nil)
  2069  
  2070  			// WHEN
  2071  			frs, err := svc.ListFetchRequestsByReferenceObjectIDsGlobal(ctx, specIDs, model.APISpecReference)
  2072  
  2073  			// then
  2074  			if testCase.ExpectedErrMessage == "" {
  2075  				require.NoError(t, err)
  2076  				assert.Equal(t, testCase.ExpectedResult, frs)
  2077  			} else {
  2078  				require.Error(t, err)
  2079  				assert.Contains(t, err.Error(), testCase.ExpectedErrMessage)
  2080  			}
  2081  
  2082  			repo.AssertExpectations(t)
  2083  		})
  2084  	}
  2085  }
  2086  
  2087  func fixUIDService() *automock.UIDService {
  2088  	svc := &automock.UIDService{}
  2089  	svc.On("Generate").Return(specID).Once()
  2090  	return svc
  2091  }