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

     1  package ord_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	directorresource "github.com/kyma-incubator/compass/components/director/pkg/resource"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/internal/model"
    10  	ord "github.com/kyma-incubator/compass/components/director/internal/open_resource_discovery"
    11  	"github.com/kyma-incubator/compass/components/director/internal/open_resource_discovery/automock"
    12  	persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock"
    13  	"github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    15  	"github.com/pkg/errors"
    16  	"github.com/stretchr/testify/mock"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestService_SyncGlobalResources(t *testing.T) {
    21  	testErr := errors.New("Test error")
    22  	txGen := txtest.NewTransactionContextGenerator(testErr)
    23  
    24  	resource := ord.Resource{
    25  		Name: "global-registry",
    26  		Type: directorresource.Application,
    27  		ID:   "global-registry",
    28  	}
    29  
    30  	testWebhook := &model.Webhook{
    31  		Type: model.WebhookTypeOpenResourceDiscovery,
    32  		URL:  str.Ptr(baseURL),
    33  	}
    34  
    35  	doc := fixGlobalRegistryORDDocument()
    36  
    37  	successfulVendorUpdate := func() *automock.GlobalVendorService {
    38  		vendorSvc := &automock.GlobalVendorService{}
    39  		vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalVendors(), nil).Once()
    40  		vendorSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), vendorID, *doc.Vendors[0]).Return(nil).Once()
    41  		vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalVendors(), nil).Once()
    42  		return vendorSvc
    43  	}
    44  
    45  	successfulVendorCreate := func() *automock.GlobalVendorService {
    46  		vendorSvc := &automock.GlobalVendorService{}
    47  		vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, nil).Once()
    48  		vendorSvc.On("CreateGlobal", txtest.CtxWithDBMatcher(), *doc.Vendors[0]).Return("", nil).Once()
    49  		vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalVendors(), nil).Once()
    50  		return vendorSvc
    51  	}
    52  
    53  	successfulProductUpdate := func() *automock.GlobalProductService {
    54  		productSvc := &automock.GlobalProductService{}
    55  		productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), nil).Once()
    56  		productSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), productID, *doc.Products[0]).Return(nil).Once()
    57  		productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), nil).Once()
    58  		return productSvc
    59  	}
    60  
    61  	successfulProductCreate := func() *automock.GlobalProductService {
    62  		productSvc := &automock.GlobalProductService{}
    63  		productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, nil).Once()
    64  		productSvc.On("CreateGlobal", txtest.CtxWithDBMatcher(), *doc.Products[0]).Return("", nil).Once()
    65  		productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), nil).Once()
    66  		return productSvc
    67  	}
    68  
    69  	successfulClientFn := func() *automock.Client {
    70  		client := &automock.Client{}
    71  		client.On("FetchOpenResourceDiscoveryDocuments", context.TODO(), resource, testWebhook).Return(ord.Documents{fixGlobalRegistryORDDocument()}, baseURL, nil)
    72  		return client
    73  	}
    74  
    75  	testCases := []struct {
    76  		Name            string
    77  		TransactionerFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
    78  		productSvcFn    func() *automock.GlobalProductService
    79  		vendorSvcFn     func() *automock.GlobalVendorService
    80  		clientFn        func() *automock.Client
    81  		ExpectedErr     error
    82  	}{
    83  		{
    84  			Name:            "Success when resources are not in db should Create them",
    85  			TransactionerFn: txGen.ThatSucceeds,
    86  			productSvcFn:    successfulProductCreate,
    87  			vendorSvcFn:     successfulVendorCreate,
    88  			clientFn:        successfulClientFn,
    89  		},
    90  		{
    91  			Name:            "Success when resources are in db should Update them",
    92  			TransactionerFn: txGen.ThatSucceeds,
    93  			productSvcFn:    successfulProductUpdate,
    94  			vendorSvcFn:     successfulVendorUpdate,
    95  			clientFn:        successfulClientFn,
    96  		},
    97  		{
    98  			Name:            "Success when resources are in db should Update them and delete all global resources that are not returned anymore",
    99  			TransactionerFn: txGen.ThatSucceeds,
   100  			productSvcFn: func() *automock.GlobalProductService {
   101  				productSvc := &automock.GlobalProductService{}
   102  				products := fixGlobalProducts()
   103  				products = append(products, &model.Product{ID: "product-id-2", OrdID: "test:product:TEST:"})
   104  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(products, nil).Once()
   105  				productSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), productID, *doc.Products[0]).Return(nil).Once()
   106  				productSvc.On("DeleteGlobal", txtest.CtxWithDBMatcher(), "product-id-2").Return(nil).Once()
   107  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), nil).Once()
   108  				return productSvc
   109  			},
   110  			vendorSvcFn: func() *automock.GlobalVendorService {
   111  				vendorSvc := &automock.GlobalVendorService{}
   112  				vendors := fixGlobalVendors()
   113  				vendors = append(vendors, &model.Vendor{ID: "vendor-id-2", OrdID: "test:vendor:TEST:"})
   114  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(vendors, nil).Once()
   115  				vendorSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), vendorID, *doc.Vendors[0]).Return(nil).Once()
   116  				vendorSvc.On("DeleteGlobal", txtest.CtxWithDBMatcher(), "vendor-id-2").Return(nil).Once()
   117  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalVendors(), nil).Once()
   118  				return vendorSvc
   119  			},
   120  			clientFn: successfulClientFn,
   121  		},
   122  		{
   123  			Name:            "Error when fetch ord docs fail",
   124  			TransactionerFn: txGen.ThatDoesntStartTransaction,
   125  			clientFn: func() *automock.Client {
   126  				client := &automock.Client{}
   127  				client.On("FetchOpenResourceDiscoveryDocuments", context.TODO(), resource, testWebhook).Return(nil, "", testErr)
   128  				return client
   129  			},
   130  			ExpectedErr: testErr,
   131  		},
   132  		{
   133  			Name:            "Error when ord docs are invalid",
   134  			TransactionerFn: txGen.ThatDoesntStartTransaction,
   135  			clientFn: func() *automock.Client {
   136  				client := &automock.Client{}
   137  				doc := fixGlobalRegistryORDDocument()
   138  				doc.Vendors[0].OrdID = "invalid-ord-id"
   139  				client.On("FetchOpenResourceDiscoveryDocuments", context.TODO(), resource, testWebhook).Return(ord.Documents{doc}, baseURL, nil)
   140  				return client
   141  			},
   142  			ExpectedErr: errors.New("ordId: must be in a valid format."),
   143  		},
   144  		{
   145  			Name:            "Error when ord docs contains resource that is not vendor or product",
   146  			TransactionerFn: txGen.ThatDoesntStartTransaction,
   147  			clientFn: func() *automock.Client {
   148  				client := &automock.Client{}
   149  				doc := fixGlobalRegistryORDDocument()
   150  				doc.ConsumptionBundles = fixORDDocument().ConsumptionBundles
   151  				client.On("FetchOpenResourceDiscoveryDocuments", context.TODO(), resource, testWebhook).Return(ord.Documents{doc}, baseURL, nil)
   152  				return client
   153  			},
   154  			ExpectedErr: errors.New("global registry supports only vendors and products"),
   155  		},
   156  		{
   157  			Name:            "Error when starting transaction fails",
   158  			TransactionerFn: txGen.ThatFailsOnBegin,
   159  			clientFn:        successfulClientFn,
   160  			ExpectedErr:     testErr,
   161  		},
   162  		{
   163  			Name:            "Error when vendor list fails",
   164  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   165  			vendorSvcFn: func() *automock.GlobalVendorService {
   166  				vendorSvc := &automock.GlobalVendorService{}
   167  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, testErr).Once()
   168  				return vendorSvc
   169  			},
   170  			clientFn:    successfulClientFn,
   171  			ExpectedErr: testErr,
   172  		},
   173  		{
   174  			Name:            "Error when vendor create fails",
   175  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   176  			vendorSvcFn: func() *automock.GlobalVendorService {
   177  				vendorSvc := &automock.GlobalVendorService{}
   178  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, nil).Once()
   179  				vendorSvc.On("CreateGlobal", txtest.CtxWithDBMatcher(), *doc.Vendors[0]).Return("", testErr).Once()
   180  				return vendorSvc
   181  			},
   182  			clientFn:    successfulClientFn,
   183  			ExpectedErr: testErr,
   184  		},
   185  		{
   186  			Name:            "Error when vendor update fails",
   187  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   188  			vendorSvcFn: func() *automock.GlobalVendorService {
   189  				vendorSvc := &automock.GlobalVendorService{}
   190  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalVendors(), nil).Once()
   191  				vendorSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), vendorID, *doc.Vendors[0]).Return(testErr).Once()
   192  				return vendorSvc
   193  			},
   194  			clientFn:    successfulClientFn,
   195  			ExpectedErr: testErr,
   196  		},
   197  		{
   198  			Name:            "Error when vendor delete fails",
   199  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   200  			vendorSvcFn: func() *automock.GlobalVendorService {
   201  				vendorSvc := &automock.GlobalVendorService{}
   202  				vendors := fixGlobalVendors()
   203  				vendors = append(vendors, &model.Vendor{ID: "vendor-id-2", OrdID: "test:vendor:TEST:"})
   204  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(vendors, nil).Once()
   205  				vendorSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), vendorID, *doc.Vendors[0]).Return(nil).Once()
   206  				vendorSvc.On("DeleteGlobal", txtest.CtxWithDBMatcher(), "vendor-id-2").Return(testErr).Once()
   207  				return vendorSvc
   208  			},
   209  			clientFn:    successfulClientFn,
   210  			ExpectedErr: testErr,
   211  		},
   212  		{
   213  			Name:            "Error when second vendor list fails",
   214  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   215  			vendorSvcFn: func() *automock.GlobalVendorService {
   216  				vendorSvc := &automock.GlobalVendorService{}
   217  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, nil).Once()
   218  				vendorSvc.On("CreateGlobal", txtest.CtxWithDBMatcher(), *doc.Vendors[0]).Return("", nil).Once()
   219  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, testErr).Once()
   220  				return vendorSvc
   221  			},
   222  			clientFn:    successfulClientFn,
   223  			ExpectedErr: testErr,
   224  		},
   225  		{
   226  			Name:            "Error when product list fails",
   227  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   228  			vendorSvcFn:     successfulVendorCreate,
   229  			productSvcFn: func() *automock.GlobalProductService {
   230  				productSvc := &automock.GlobalProductService{}
   231  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, testErr).Once()
   232  				return productSvc
   233  			},
   234  			clientFn:    successfulClientFn,
   235  			ExpectedErr: testErr,
   236  		},
   237  		{
   238  			Name:            "Error when product create fails",
   239  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   240  			vendorSvcFn:     successfulVendorCreate,
   241  			productSvcFn: func() *automock.GlobalProductService {
   242  				productSvc := &automock.GlobalProductService{}
   243  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, nil).Once()
   244  				productSvc.On("CreateGlobal", txtest.CtxWithDBMatcher(), *doc.Products[0]).Return("", testErr).Once()
   245  				return productSvc
   246  			},
   247  			clientFn:    successfulClientFn,
   248  			ExpectedErr: testErr,
   249  		},
   250  		{
   251  			Name:            "Error when product update fails",
   252  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   253  			vendorSvcFn:     successfulVendorCreate,
   254  			productSvcFn: func() *automock.GlobalProductService {
   255  				productSvc := &automock.GlobalProductService{}
   256  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), nil).Once()
   257  				productSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), productID, *doc.Products[0]).Return(testErr).Once()
   258  				return productSvc
   259  			},
   260  			clientFn:    successfulClientFn,
   261  			ExpectedErr: testErr,
   262  		},
   263  		{
   264  			Name:            "Error when product delete fails",
   265  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   266  			vendorSvcFn:     successfulVendorCreate,
   267  			productSvcFn: func() *automock.GlobalProductService {
   268  				productSvc := &automock.GlobalProductService{}
   269  				products := fixGlobalProducts()
   270  				products = append(products, &model.Product{ID: "product-id-2", OrdID: "test:product:TEST:"})
   271  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(products, nil).Once()
   272  				productSvc.On("UpdateGlobal", txtest.CtxWithDBMatcher(), productID, *doc.Products[0]).Return(nil).Once()
   273  				productSvc.On("DeleteGlobal", txtest.CtxWithDBMatcher(), "product-id-2").Return(testErr).Once()
   274  				return productSvc
   275  			},
   276  			clientFn:    successfulClientFn,
   277  			ExpectedErr: testErr,
   278  		},
   279  		{
   280  			Name:            "Error when second product list fails",
   281  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   282  			vendorSvcFn:     successfulVendorCreate,
   283  			productSvcFn: func() *automock.GlobalProductService {
   284  				productSvc := &automock.GlobalProductService{}
   285  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, nil).Once()
   286  				productSvc.On("CreateGlobal", txtest.CtxWithDBMatcher(), *doc.Products[0]).Return("", nil).Once()
   287  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), testErr).Once()
   288  				return productSvc
   289  			},
   290  			clientFn:    successfulClientFn,
   291  			ExpectedErr: testErr,
   292  		},
   293  		{
   294  			Name:            "Error when transaction commit fails",
   295  			TransactionerFn: txGen.ThatFailsOnCommit,
   296  			productSvcFn:    successfulProductCreate,
   297  			vendorSvcFn:     successfulVendorCreate,
   298  			clientFn:        successfulClientFn,
   299  			ExpectedErr:     testErr,
   300  		},
   301  	}
   302  
   303  	for _, test := range testCases {
   304  		t.Run(test.Name, func(t *testing.T) {
   305  			_, tx := test.TransactionerFn()
   306  			productSvc := &automock.GlobalProductService{}
   307  			if test.productSvcFn != nil {
   308  				productSvc = test.productSvcFn()
   309  			}
   310  			vendorSvc := &automock.GlobalVendorService{}
   311  			if test.vendorSvcFn != nil {
   312  				vendorSvc = test.vendorSvcFn()
   313  			}
   314  			client := &automock.Client{}
   315  			if test.clientFn != nil {
   316  				client = test.clientFn()
   317  			}
   318  
   319  			svc := ord.NewGlobalRegistryService(tx, ord.GlobalRegistryConfig{URL: baseURL}, vendorSvc, productSvc, client, credentialExchangeStrategyTenantMappings)
   320  			globalIDs, err := svc.SyncGlobalResources(context.TODO())
   321  			if test.ExpectedErr != nil {
   322  				require.Error(t, err)
   323  				require.Contains(t, err.Error(), test.ExpectedErr.Error())
   324  			} else {
   325  				require.NoError(t, err)
   326  				require.Len(t, globalIDs, 2)
   327  				require.True(t, globalIDs[vendorORDID])
   328  				require.True(t, globalIDs[globalProductORDID])
   329  			}
   330  
   331  			mock.AssertExpectationsForObjects(t, tx, productSvc, vendorSvc, client)
   332  		})
   333  	}
   334  }
   335  
   336  func TestService_ListGlobalResources(t *testing.T) {
   337  	testErr := errors.New("Test error")
   338  	txGen := txtest.NewTransactionContextGenerator(testErr)
   339  
   340  	successfulVendorList := func() *automock.GlobalVendorService {
   341  		vendorSvc := &automock.GlobalVendorService{}
   342  		vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalVendors(), nil).Once()
   343  		return vendorSvc
   344  	}
   345  
   346  	successfulProductList := func() *automock.GlobalProductService {
   347  		productSvc := &automock.GlobalProductService{}
   348  		productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(fixGlobalProducts(), nil).Once()
   349  		return productSvc
   350  	}
   351  
   352  	testCases := []struct {
   353  		Name            string
   354  		TransactionerFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
   355  		productSvcFn    func() *automock.GlobalProductService
   356  		vendorSvcFn     func() *automock.GlobalVendorService
   357  		ExpectedErr     error
   358  	}{
   359  		{
   360  			Name:            "Success",
   361  			TransactionerFn: txGen.ThatSucceeds,
   362  			productSvcFn:    successfulProductList,
   363  			vendorSvcFn:     successfulVendorList,
   364  		},
   365  		{
   366  			Name:            "Error when vendor list fails",
   367  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   368  			vendorSvcFn: func() *automock.GlobalVendorService {
   369  				vendorSvc := &automock.GlobalVendorService{}
   370  				vendorSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, testErr).Once()
   371  				return vendorSvc
   372  			},
   373  			ExpectedErr: testErr,
   374  		},
   375  		{
   376  			Name:            "Error when product list fails",
   377  			TransactionerFn: txGen.ThatDoesntExpectCommit,
   378  			vendorSvcFn:     successfulVendorList,
   379  			productSvcFn: func() *automock.GlobalProductService {
   380  				productSvc := &automock.GlobalProductService{}
   381  				productSvc.On("ListGlobal", txtest.CtxWithDBMatcher()).Return(nil, testErr).Once()
   382  				return productSvc
   383  			},
   384  			ExpectedErr: testErr,
   385  		},
   386  		{
   387  			Name:            "Error when transaction commit fails",
   388  			TransactionerFn: txGen.ThatFailsOnCommit,
   389  			productSvcFn:    successfulProductList,
   390  			vendorSvcFn:     successfulVendorList,
   391  			ExpectedErr:     testErr,
   392  		},
   393  		{
   394  			Name:            "Error when transaction begin fails",
   395  			TransactionerFn: txGen.ThatFailsOnBegin,
   396  			ExpectedErr:     testErr,
   397  		},
   398  	}
   399  
   400  	for _, test := range testCases {
   401  		t.Run(test.Name, func(t *testing.T) {
   402  			_, tx := test.TransactionerFn()
   403  			productSvc := &automock.GlobalProductService{}
   404  			if test.productSvcFn != nil {
   405  				productSvc = test.productSvcFn()
   406  			}
   407  			vendorSvc := &automock.GlobalVendorService{}
   408  			if test.vendorSvcFn != nil {
   409  				vendorSvc = test.vendorSvcFn()
   410  			}
   411  			client := &automock.Client{}
   412  
   413  			svc := ord.NewGlobalRegistryService(tx, ord.GlobalRegistryConfig{URL: baseURL}, vendorSvc, productSvc, client, credentialExchangeStrategyTenantMappings)
   414  			globalIDs, err := svc.ListGlobalResources(context.TODO())
   415  			if test.ExpectedErr != nil {
   416  				require.Error(t, err)
   417  				require.Contains(t, err.Error(), test.ExpectedErr.Error())
   418  			} else {
   419  				require.NoError(t, err)
   420  				require.Len(t, globalIDs, 2)
   421  				require.True(t, globalIDs[vendorORDID])
   422  				require.True(t, globalIDs[globalProductORDID])
   423  			}
   424  
   425  			mock.AssertExpectationsForObjects(t, tx, productSvc, vendorSvc, client)
   426  		})
   427  	}
   428  }