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 }