github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/systemfetcher/loader_test.go (about) 1 package systemfetcher_test 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io/fs" 8 "os" 9 "testing" 10 11 "github.com/kyma-incubator/compass/components/director/internal/model" 12 "github.com/kyma-incubator/compass/components/director/internal/systemfetcher" 13 "github.com/kyma-incubator/compass/components/director/internal/systemfetcher/automock" 14 "github.com/kyma-incubator/compass/components/director/pkg/pagination" 15 pAutomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock" 16 "github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest" 17 "github.com/kyma-incubator/compass/components/director/pkg/str" 18 "github.com/stretchr/testify/mock" 19 "github.com/stretchr/testify/require" 20 ) 21 22 const tempFileName = "tmp.json" 23 24 func TestLoadData(t *testing.T) { 25 testErr := errors.New("testErr") 26 whID1 := "123456789" 27 whID2 := "123456789-new" 28 whType := model.WebhookModeAsyncCallback 29 30 applicationTemplateName := "app-tmpl-name" 31 applicationTemplatesJSON := "[{" + 32 "\"name\":\"" + applicationTemplateName + "\"," + 33 "\"description\":\"app-tmpl-desc\"}]" 34 applicationTemplatesWithIntSysJSON := "[{" + 35 "\"name\":\"" + applicationTemplateName + "\"," + 36 "\"applicationInputJSON\":\"{\\\"name\\\": \\\"name\\\", \\\"labels\\\": {\\\"legacy\\\": \\\"true\\\"}}\"," + 37 "\"intSystem\":{" + 38 "\"name\":\"int-sys-name\"," + 39 "\"description\":\"int-sys-desc\"}," + 40 "\"description\":\"app-tmpl-desc\"}]" 41 42 applicationTemplatesWithIntSysJSONAndPlaceholders := "[{" + 43 "\"name\":\"" + applicationTemplateName + "\"," + 44 "\"applicationInputJSON\":\"{\\\"name\\\": \\\"name\\\", \\\"labels\\\": {\\\"legacy\\\":\\\"true\\\"}}\"," + 45 "\"placeholders\":[{\"name\":\"name\",\"description\": \"description\",\"jsonPath\": \"jsonPath\"}]," + 46 "\"labels\":{\"managed_app_provisioning\":false}," + 47 "\"intSystem\":{" + 48 "\"name\":\"int-sys-name\"," + 49 "\"description\":\"int-sys-desc\"}," + 50 "\"description\":\"app-tmpl-desc\"}]" 51 52 applicationTemplatesWithIntSysJSONAndWebhooks := "[{" + 53 "\"name\":\"" + applicationTemplateName + "\"," + 54 "\"webhooks\":[{\"id\":\"" + whID1 + "\", \"objectID\":\"" + whID1 + "\", \"objectType\": \"ApplicationWebhook\", \"type\": \"CONFIGURATION_CHANGED\", \"mode\": \"ASYNC_CALLBACK\" },{\"id\":\"" + whID2 + "\", \"objectID\":\"" + whID2 + "\", \"objectType\": \"ApplicationWebhook\", \"type\": \"CONFIGURATION_CHANGED\", \"mode\": \"ASYNC_CALLBACK\" }]," + 55 "\"applicationInputJSON\":\"{\\\"name\\\": \\\"name\\\", \\\"labels\\\": {\\\"legacy\\\":\\\"true\\\"}}\"," + 56 "\"placeholders\":[{\"name\":\"name\",\"description\": \"description\",\"jsonPath\": \"jsonPath\"}]," + 57 "\"intSystem\":{" + 58 "\"name\":\"int-sys-name\"," + 59 "\"description\":\"int-sys-desc\"}," + 60 "\"description\":\"app-tmpl-desc\"}]" 61 62 pageInfo := &pagination.Page{ 63 StartCursor: "", 64 EndCursor: "", 65 HasNextPage: false, 66 } 67 68 intSysPage := model.IntegrationSystemPage{ 69 Data: []*model.IntegrationSystem{ 70 { 71 ID: "id", 72 Name: "name", 73 Description: str.Ptr("desc"), 74 }, 75 }, 76 PageInfo: pageInfo, 77 TotalCount: 0, 78 } 79 80 type testCase struct { 81 name string 82 mockTransactioner func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) 83 appTmplSvc func() *automock.AppTmplService 84 intSysSvc func() *automock.IntSysSvc 85 readDirFunc func(path string) ([]os.DirEntry, error) 86 readFileFunc func(path string) ([]byte, error) 87 expectedErr error 88 } 89 tests := []testCase{ 90 { 91 name: "load application templates failed - read dir returns error", 92 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 93 return txtest.NewTransactionContextGenerator(nil).ThatDoesntStartTransaction() 94 }, 95 appTmplSvc: mockAppTmplService, 96 intSysSvc: mockIntSysService, 97 readDirFunc: func(path string) ([]os.DirEntry, error) { 98 return nil, testErr 99 }, 100 readFileFunc: mockReadFile, 101 expectedErr: testErr, 102 }, 103 { 104 name: "load application templates failed - unsupported file type", 105 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 106 return txtest.NewTransactionContextGenerator(nil).ThatDoesntStartTransaction() 107 }, 108 appTmplSvc: mockAppTmplService, 109 intSysSvc: mockIntSysService, 110 readDirFunc: func(path string) ([]os.DirEntry, error) { 111 file := FakeFile{name: "test.txt"} 112 return []os.DirEntry{&file}, nil 113 }, 114 readFileFunc: mockReadFile, 115 expectedErr: fmt.Errorf("unsupported file format \".txt\", supported format: json"), 116 }, 117 { 118 name: "load application templates failed - read file returns error", 119 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 120 return txtest.NewTransactionContextGenerator(nil).ThatDoesntStartTransaction() 121 }, 122 appTmplSvc: mockAppTmplService, 123 intSysSvc: mockIntSysService, 124 readDirFunc: mockReadDir, 125 readFileFunc: func(path string) ([]byte, error) { 126 return []byte("[]"), testErr 127 }, 128 expectedErr: testErr, 129 }, 130 { 131 name: "begin transaction failed", 132 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 133 return txtest.NewTransactionContextGenerator(testErr).ThatFailsOnBegin() 134 }, 135 appTmplSvc: mockAppTmplService, 136 intSysSvc: mockIntSysService, 137 readDirFunc: mockReadDir, 138 readFileFunc: mockReadFile, 139 expectedErr: testErr, 140 }, 141 { 142 name: "upsert application templates failed - GetByNameAndRegion returns error", 143 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 144 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 145 }, 146 appTmplSvc: func() *automock.AppTmplService { 147 appTmplSvc := &automock.AppTmplService{} 148 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(nil, testErr).Once() 149 return appTmplSvc 150 }, 151 intSysSvc: mockIntSysService, 152 readDirFunc: mockReadDir, 153 readFileFunc: func(path string) ([]byte, error) { 154 return []byte(applicationTemplatesJSON), nil 155 }, 156 expectedErr: testErr, 157 }, 158 { 159 name: "upsert application templates failed - create returns error", 160 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 161 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 162 }, 163 appTmplSvc: func() *automock.AppTmplService { 164 appTmplSvc := &automock.AppTmplService{} 165 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(nil, fmt.Errorf("Object not found")).Once() 166 appTmplSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationTemplateInput")).Return("", testErr).Once() 167 return appTmplSvc 168 }, 169 intSysSvc: mockIntSysService, 170 readDirFunc: mockReadDir, 171 readFileFunc: func(path string) ([]byte, error) { 172 return []byte(applicationTemplatesJSON), nil 173 }, 174 expectedErr: testErr, 175 }, 176 { 177 name: "commit returns error", 178 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 179 return txtest.NewTransactionContextGenerator(testErr).ThatFailsOnCommit() 180 }, 181 appTmplSvc: func() *automock.AppTmplService { 182 appTmplSvc := &automock.AppTmplService{} 183 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(nil, fmt.Errorf("Object not found")).Once() 184 appTmplSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationTemplateInput")).Return("", nil).Once() 185 return appTmplSvc 186 }, 187 intSysSvc: mockIntSysService, 188 readDirFunc: mockReadDir, 189 readFileFunc: func(path string) ([]byte, error) { 190 return []byte(applicationTemplatesJSON), nil 191 }, 192 expectedErr: testErr, 193 }, 194 { 195 name: "create application templates dependent entities failed - invalid intSys json object", 196 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 197 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 198 }, 199 appTmplSvc: mockAppTmplService, 200 intSysSvc: mockIntSysService, 201 readDirFunc: mockReadDir, 202 readFileFunc: func(path string) ([]byte, error) { 203 applicationTemplatesWithInvalidIntSysJSON := "[{" + 204 "\"name\":\"" + applicationTemplateName + "\"," + 205 "\"intSystem\":123," + 206 "\"description\":\"app-tmpl-desc\"}]" 207 return []byte(applicationTemplatesWithInvalidIntSysJSON), nil 208 }, 209 expectedErr: errors.New("the type of the integration system is float64 instead of map[string]interface{}. map[]"), 210 }, 211 { 212 name: "extract integration system failed - invalid intSys name json field", 213 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 214 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 215 }, 216 appTmplSvc: mockAppTmplService, 217 intSysSvc: mockIntSysService, 218 readDirFunc: mockReadDir, 219 readFileFunc: func(path string) ([]byte, error) { 220 applicationTemplatesWithInvalidIntSysNameJSON := "[{" + 221 "\"name\":\"" + applicationTemplateName + "\"," + 222 "\"intSystem\":{" + 223 "\"name\":123," + 224 "\"description\":\"int-sys-desc\"}," + 225 "\"description\":\"app-tmpl-desc\"}]" 226 return []byte(applicationTemplatesWithInvalidIntSysNameJSON), nil 227 }, 228 expectedErr: errors.New("integration system name value must be string"), 229 }, 230 { 231 name: "extract integration system failed - invalid intSys description json field", 232 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 233 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 234 }, 235 appTmplSvc: mockAppTmplService, 236 intSysSvc: mockIntSysService, 237 readDirFunc: mockReadDir, 238 readFileFunc: func(path string) ([]byte, error) { 239 applicationTemplatesWithInvalidIntSysDescJSON := "[{" + 240 "\"name\":\"" + applicationTemplateName + "\"," + 241 "\"intSystem\":{" + 242 "\"name\":\"int-sys-name\"," + 243 "\"description\":123}," + 244 "\"description\":\"app-tmpl-desc\"}]" 245 return []byte(applicationTemplatesWithInvalidIntSysDescJSON), nil 246 }, 247 expectedErr: errors.New("integration system description value must be string"), 248 }, 249 { 250 name: "extract integration system failed - missing intSys name json field", 251 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 252 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 253 }, 254 appTmplSvc: mockAppTmplService, 255 intSysSvc: mockIntSysService, 256 readDirFunc: mockReadDir, 257 readFileFunc: func(path string) ([]byte, error) { 258 applicationTemplatesWithMissingIntSysNameJSON := "[{" + 259 "\"name\":\"" + applicationTemplateName + "\"," + 260 "\"intSystem\":{" + 261 "\"description\":123}," + 262 "\"description\":\"app-tmpl-desc\"}]" 263 return []byte(applicationTemplatesWithMissingIntSysNameJSON), nil 264 }, 265 expectedErr: errors.New("integration system name is missing"), 266 }, 267 { 268 name: "extract integration system failed - missing intSys description json field", 269 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 270 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 271 }, 272 appTmplSvc: mockAppTmplService, 273 intSysSvc: mockIntSysService, 274 readDirFunc: mockReadDir, 275 readFileFunc: func(path string) ([]byte, error) { 276 applicationTemplatesWithMissingIntSysDescJSON := "[{" + 277 "\"name\":\"" + applicationTemplateName + "\"," + 278 "\"intSystem\":{" + 279 "\"name\":\"int-sys-name\"}," + 280 "\"description\":\"app-tmpl-desc\"}]" 281 return []byte(applicationTemplatesWithMissingIntSysDescJSON), nil 282 }, 283 expectedErr: errors.New("integration system description is missing"), 284 }, 285 { 286 name: "list integration systems failed - list returns error", 287 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 288 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 289 }, 290 appTmplSvc: mockAppTmplService, 291 intSysSvc: func() *automock.IntSysSvc { 292 intSysSvc := &automock.IntSysSvc{} 293 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(model.IntegrationSystemPage{}, testErr).Once() 294 return intSysSvc 295 }, 296 readDirFunc: mockReadDir, 297 readFileFunc: func(path string) ([]byte, error) { 298 return []byte(applicationTemplatesWithIntSysJSON), nil 299 }, 300 expectedErr: testErr, 301 }, 302 { 303 name: "create app templates dependent entities failed - create integration system returns error", 304 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 305 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 306 }, 307 appTmplSvc: mockAppTmplService, 308 intSysSvc: func() *automock.IntSysSvc { 309 intSysSvc := &automock.IntSysSvc{} 310 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 311 intSysSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.IntegrationSystemInput")).Return("", testErr).Once() 312 return intSysSvc 313 }, 314 readDirFunc: mockReadDir, 315 readFileFunc: func(path string) ([]byte, error) { 316 return []byte(applicationTemplatesWithIntSysJSON), nil 317 }, 318 expectedErr: testErr, 319 }, 320 { 321 name: "upsert application template failed - update returns error", 322 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 323 return txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit() 324 }, 325 appTmplSvc: func() *automock.AppTmplService { 326 template := model.ApplicationTemplate{ 327 ID: "id", 328 ApplicationInputJSON: "{\"test\":\"test\"}", 329 } 330 appTmplSvc := &automock.AppTmplService{} 331 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(&template, nil).Once() 332 appTmplSvc.On("Update", txtest.CtxWithDBMatcher(), "id", mock.AnythingOfType("model.ApplicationTemplateUpdateInput")).Return(testErr).Once() 333 return appTmplSvc 334 }, 335 intSysSvc: func() *automock.IntSysSvc { 336 intSysPage := model.IntegrationSystemPage{ 337 Data: []*model.IntegrationSystem{ 338 { 339 ID: "id", 340 Name: "int-sys-name", 341 Description: str.Ptr("int-sys-desc"), 342 }, 343 }, 344 PageInfo: pageInfo, 345 TotalCount: 0, 346 } 347 intSysSvc := &automock.IntSysSvc{} 348 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 349 return intSysSvc 350 }, 351 readDirFunc: mockReadDir, 352 readFileFunc: func(path string) ([]byte, error) { 353 return []byte(applicationTemplatesWithIntSysJSON), nil 354 }, 355 expectedErr: testErr, 356 }, 357 { 358 name: "Success", 359 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 360 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 361 }, 362 appTmplSvc: func() *automock.AppTmplService { 363 appTmplSvc := &automock.AppTmplService{} 364 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(nil, fmt.Errorf("Object not found")).Once() 365 appTmplSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationTemplateInput")).Return("", nil).Once() 366 return appTmplSvc 367 }, 368 intSysSvc: func() *automock.IntSysSvc { 369 intSysSvc := &automock.IntSysSvc{} 370 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 371 intSysSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.IntegrationSystemInput")).Return("int-sys-id", nil).Once() 372 return intSysSvc 373 }, 374 readDirFunc: mockReadDir, 375 readFileFunc: func(path string) ([]byte, error) { 376 return []byte(applicationTemplatesWithIntSysJSON), nil 377 }, 378 }, 379 { 380 name: "Success - integration system already exists", 381 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 382 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 383 }, 384 appTmplSvc: func() *automock.AppTmplService { 385 appTmplSvc := &automock.AppTmplService{} 386 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(nil, fmt.Errorf("Object not found")).Once() 387 appTmplSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationTemplateInput")).Return("", nil).Once() 388 return appTmplSvc 389 }, 390 intSysSvc: func() *automock.IntSysSvc { 391 intSysPage := model.IntegrationSystemPage{ 392 Data: []*model.IntegrationSystem{ 393 { 394 ID: "id", 395 Name: "int-sys-name", 396 Description: str.Ptr("int-sys-desc"), 397 }, 398 }, 399 PageInfo: pageInfo, 400 TotalCount: 0, 401 } 402 intSysSvc := &automock.IntSysSvc{} 403 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 404 return intSysSvc 405 }, 406 readDirFunc: mockReadDir, 407 readFileFunc: func(path string) ([]byte, error) { 408 return []byte(applicationTemplatesWithIntSysJSON), nil 409 }, 410 }, 411 { 412 name: "Success - application template already exists, update triggered", 413 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 414 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 415 }, 416 appTmplSvc: func() *automock.AppTmplService { 417 template := model.ApplicationTemplate{ 418 ID: "id", 419 ApplicationInputJSON: "{\"test\":\"test\"}", 420 } 421 appTmplSvc := &automock.AppTmplService{} 422 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(&template, nil).Once() 423 appTmplSvc.On("Update", txtest.CtxWithDBMatcher(), "id", mock.AnythingOfType("model.ApplicationTemplateUpdateInput")).Return(nil).Once() 424 return appTmplSvc 425 }, 426 intSysSvc: func() *automock.IntSysSvc { 427 intSysPage := model.IntegrationSystemPage{ 428 Data: []*model.IntegrationSystem{ 429 { 430 ID: "id", 431 Name: "int-sys-name", 432 Description: str.Ptr("int-sys-desc"), 433 }, 434 }, 435 PageInfo: pageInfo, 436 TotalCount: 0, 437 } 438 intSysSvc := &automock.IntSysSvc{} 439 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 440 return intSysSvc 441 }, 442 readDirFunc: mockReadDir, 443 readFileFunc: func(path string) ([]byte, error) { 444 return []byte(applicationTemplatesWithIntSysJSON), nil 445 }, 446 }, 447 { 448 name: "Success - application template already exists, update triggered when only labels are different", 449 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 450 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 451 }, 452 appTmplSvc: func() *automock.AppTmplService { 453 template := model.ApplicationTemplate{ 454 ID: "id", 455 Name: "app-tmpl-name", 456 Description: str.Ptr("app-tmpl-desc"), 457 ApplicationInputJSON: "{\"integrationSystemID\":\"id\",\"labels\":{\"legacy\":\"true\"},\"name\":\"name\"}", 458 Placeholders: []model.ApplicationTemplatePlaceholder{ 459 { 460 Name: "name", 461 Description: str.Ptr("description"), 462 JSONPath: str.Ptr("jsonPath"), 463 }, 464 }, 465 Labels: map[string]interface{}{ 466 "managed_app_provisioning": true, 467 }, 468 } 469 appTmplSvc := &automock.AppTmplService{} 470 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(&template, nil).Once() 471 appTmplSvc.On("Update", txtest.CtxWithDBMatcher(), "id", mock.AnythingOfType("model.ApplicationTemplateUpdateInput")).Return(nil).Once() 472 return appTmplSvc 473 }, 474 intSysSvc: func() *automock.IntSysSvc { 475 intSysPage := model.IntegrationSystemPage{ 476 Data: []*model.IntegrationSystem{ 477 { 478 ID: "id", 479 Name: "int-sys-name", 480 Description: str.Ptr("int-sys-desc"), 481 }, 482 }, 483 PageInfo: pageInfo, 484 TotalCount: 0, 485 } 486 intSysSvc := &automock.IntSysSvc{} 487 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 488 return intSysSvc 489 }, 490 readDirFunc: mockReadDir, 491 readFileFunc: func(path string) ([]byte, error) { 492 return []byte(applicationTemplatesWithIntSysJSONAndPlaceholders), nil 493 }, 494 }, 495 { 496 name: "Success - integration system already exists, missing labels in applicationInputJSON", 497 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 498 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 499 }, 500 appTmplSvc: func() *automock.AppTmplService { 501 appTmplSvc := &automock.AppTmplService{} 502 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(nil, fmt.Errorf("Object not found")).Once() 503 appTmplSvc.On("Create", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationTemplateInput")).Return("", nil).Once() 504 return appTmplSvc 505 }, 506 intSysSvc: func() *automock.IntSysSvc { 507 intSysPage := model.IntegrationSystemPage{ 508 Data: []*model.IntegrationSystem{ 509 { 510 ID: "id", 511 Name: "int-sys-name", 512 Description: str.Ptr("int-sys-desc"), 513 }, 514 }, 515 PageInfo: pageInfo, 516 TotalCount: 0, 517 } 518 intSysSvc := &automock.IntSysSvc{} 519 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 520 return intSysSvc 521 }, 522 readDirFunc: mockReadDir, 523 readFileFunc: func(path string) ([]byte, error) { 524 applicationTemplatesWithIntSysAndMissingLabelsJSON := "[{" + 525 "\"name\":\"" + applicationTemplateName + "\"," + 526 "\"applicationInputJSON\":\"{\\\"name\\\": \\\"name\\\"}\"," + 527 "\"intSystem\":{" + 528 "\"name\":\"int-sys-name\"," + 529 "\"description\":\"int-sys-desc\"}," + 530 "\"description\":\"app-tmpl-desc\"}]" 531 return []byte(applicationTemplatesWithIntSysAndMissingLabelsJSON), nil 532 }, 533 }, 534 { 535 name: "Success - application template already exists, update triggered when only webhooks length is different", 536 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 537 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 538 }, 539 appTmplSvc: func() *automock.AppTmplService { 540 template := model.ApplicationTemplate{ 541 ID: "id", 542 Name: "app-tmpl-name", 543 Description: str.Ptr("app-tmpl-desc"), 544 ApplicationInputJSON: "{\"integrationSystemID\":\"id\",\"labels\":{\"legacy\":\"true\"},\"name\":\"name\"}", 545 Placeholders: []model.ApplicationTemplatePlaceholder{ 546 { 547 Name: "name", 548 Description: str.Ptr("description"), 549 JSONPath: str.Ptr("jsonPath"), 550 }, 551 }, 552 Labels: map[string]interface{}{ 553 "managed_app_provisioning": false, 554 }, 555 Webhooks: []model.Webhook{ 556 fixWebhookModel(whID1, whType), 557 }, 558 } 559 appTmplSvc := &automock.AppTmplService{} 560 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(&template, nil).Once() 561 appTmplSvc.On("Update", txtest.CtxWithDBMatcher(), "id", mock.AnythingOfType("model.ApplicationTemplateUpdateInput")).Return(nil).Once() 562 return appTmplSvc 563 }, 564 intSysSvc: func() *automock.IntSysSvc { 565 intSysPage := model.IntegrationSystemPage{ 566 Data: []*model.IntegrationSystem{ 567 { 568 ID: "id", 569 Name: "int-sys-name", 570 Description: str.Ptr("int-sys-desc"), 571 }, 572 }, 573 PageInfo: pageInfo, 574 TotalCount: 0, 575 } 576 intSysSvc := &automock.IntSysSvc{} 577 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 578 return intSysSvc 579 }, 580 readDirFunc: mockReadDir, 581 readFileFunc: func(path string) ([]byte, error) { 582 return []byte(applicationTemplatesWithIntSysJSONAndWebhooks), nil 583 }, 584 }, 585 { 586 name: "Success - application template already exists, update triggered when only webhooks internals are different", 587 mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) { 588 return txtest.NewTransactionContextGenerator(nil).ThatSucceeds() 589 }, 590 appTmplSvc: func() *automock.AppTmplService { 591 template := model.ApplicationTemplate{ 592 ID: "id", 593 Name: "app-tmpl-name", 594 Description: str.Ptr("app-tmpl-desc"), 595 ApplicationInputJSON: "{\"integrationSystemID\":\"id\",\"labels\":{\"legacy\":\"true\"},\"name\":\"name\"}", 596 Placeholders: []model.ApplicationTemplatePlaceholder{ 597 { 598 Name: "name", 599 Description: str.Ptr("description"), 600 JSONPath: str.Ptr("jsonPath"), 601 }, 602 }, 603 Labels: map[string]interface{}{ 604 "managed_app_provisioning": false, 605 }, 606 Webhooks: []model.Webhook{ 607 fixWebhookModel(whID1, whType), 608 fixWebhookModel(whID2, model.WebhookModeSync), 609 }, 610 } 611 appTmplSvc := &automock.AppTmplService{} 612 appTmplSvc.On("GetByNameAndRegion", txtest.CtxWithDBMatcher(), applicationTemplateName, nil).Return(&template, nil).Once() 613 appTmplSvc.On("Update", txtest.CtxWithDBMatcher(), "id", mock.AnythingOfType("model.ApplicationTemplateUpdateInput")).Return(nil).Once() 614 return appTmplSvc 615 }, 616 intSysSvc: func() *automock.IntSysSvc { 617 intSysPage := model.IntegrationSystemPage{ 618 Data: []*model.IntegrationSystem{ 619 { 620 ID: "id", 621 Name: "int-sys-name", 622 Description: str.Ptr("int-sys-desc"), 623 }, 624 }, 625 PageInfo: pageInfo, 626 TotalCount: 0, 627 } 628 intSysSvc := &automock.IntSysSvc{} 629 intSysSvc.On("List", txtest.CtxWithDBMatcher(), 200, "").Return(intSysPage, nil).Once() 630 return intSysSvc 631 }, 632 readDirFunc: mockReadDir, 633 readFileFunc: func(path string) ([]byte, error) { 634 return []byte(applicationTemplatesWithIntSysJSONAndWebhooks), nil 635 }, 636 }, 637 } 638 639 for _, testCase := range tests { 640 t.Run(testCase.name, func(t *testing.T) { 641 appTmplSvc := testCase.appTmplSvc() 642 intSysSvc := testCase.intSysSvc() 643 mockedTx, transactioner := testCase.mockTransactioner() 644 defer mock.AssertExpectationsForObjects(t, appTmplSvc, intSysSvc, mockedTx, transactioner) 645 646 dataLoader := systemfetcher.NewDataLoader(transactioner, systemfetcher.Config{}, appTmplSvc, intSysSvc) 647 err := dataLoader.LoadData(context.TODO(), testCase.readDirFunc, testCase.readFileFunc) 648 649 if testCase.expectedErr != nil { 650 require.Contains(t, err.Error(), testCase.expectedErr.Error()) 651 } else { 652 require.NoError(t, err) 653 } 654 }) 655 } 656 } 657 658 func mockReadFile(_ string) ([]byte, error) { 659 return []byte("[]"), nil 660 } 661 662 func mockReadDir(_ string) ([]os.DirEntry, error) { 663 file := FakeFile{name: tempFileName} 664 return []os.DirEntry{&file}, nil 665 } 666 667 func mockAppTmplService() *automock.AppTmplService { 668 return &automock.AppTmplService{} 669 } 670 671 func mockIntSysService() *automock.IntSysSvc { 672 return &automock.IntSysSvc{} 673 } 674 675 type FakeFile struct { 676 name string 677 } 678 679 func (f *FakeFile) Type() fs.FileMode { 680 return 0 681 } 682 683 func (f *FakeFile) Info() (fs.FileInfo, error) { 684 return nil, nil 685 } 686 687 func (f *FakeFile) Name() string { 688 return f.name 689 } 690 691 func (f *FakeFile) IsDir() bool { 692 return false 693 }