github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/formationmapping/handler_test.go (about) 1 package formationmapping_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "net/http/httptest" 10 "testing" 11 12 persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock" 13 "github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest" 14 15 "github.com/kyma-incubator/compass/components/director/internal/domain/formationassignment" 16 "github.com/kyma-incubator/compass/components/director/internal/formationmapping/automock" 17 "github.com/kyma-incubator/compass/components/director/internal/model" 18 "github.com/stretchr/testify/mock" 19 20 "github.com/kyma-incubator/compass/components/director/pkg/httputils" 21 22 "github.com/gorilla/mux" 23 fm "github.com/kyma-incubator/compass/components/director/internal/formationmapping" 24 "github.com/stretchr/testify/require" 25 ) 26 27 // todo::: revert and fix unit test 28 //func TestHandler_UpdateFormationAssignmentStatus(t *testing.T) { 29 // url := fmt.Sprintf("/v1/businessIntegrations/{%s}/assignments/{%s}/status", fm.FormationIDParam, fm.FormationAssignmentIDParam) 30 // testValidConfig := `{"testK":"testV"}` 31 // urlVars := map[string]string{ 32 // fm.FormationIDParam: testFormationID, 33 // fm.FormationAssignmentIDParam: testFormationAssignmentID, 34 // } 35 // configurationErr := errors.New("formation assignment configuration error") 36 // 37 // // formation assignment fixtures with ASSIGN operation 38 // faWithSourceAppAndTargetRuntime := fixFormationAssignmentModelWithStateAndConfig(testFormationAssignmentID, testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntime, model.ReadyAssignmentState, testValidConfig) 39 // reverseFAWithSourceRuntimeAndTargetApp := fixFormationAssignmentModelWithStateAndConfig(testFormationAssignmentID, testFormationID, internalTntID, faTargetID, faSourceID, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeApplication, model.ReadyAssignmentState, testValidConfig) 40 // 41 // faWithSourceAppAndTargetRuntimeWithCreateErrorState := fixFormationAssignmentModelWithStateAndConfig(testFormationAssignmentID, testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntime, model.CreateErrorAssignmentState, "") 42 // 43 // testFAReqMapping := formationassignment.FormationAssignmentRequestMapping{ 44 // Request: fixEmptyNotificationRequest(), 45 // FormationAssignment: faWithSourceAppAndTargetRuntime, 46 // } 47 // 48 // testReverseFAReqMapping := formationassignment.FormationAssignmentRequestMapping{ 49 // Request: fixEmptyNotificationRequest(), 50 // FormationAssignment: reverseFAWithSourceRuntimeAndTargetApp, 51 // } 52 // 53 // testAssignmentPair := &formationassignment.AssignmentMappingPairWithOperation{ 54 // AssignmentMappingPair: &formationassignment.AssignmentMappingPair{ 55 // Assignment: &testReverseFAReqMapping, 56 // ReverseAssignment: &testFAReqMapping, 57 // }, 58 // Operation: model.AssignFormation, 59 // } 60 // 61 // // formation assignment fixtures with UNASSIGN operation 62 // faWithSourceAppAndTargetRuntimeForUnassingOp := fixFormationAssignmentModelWithStateAndConfig(testFormationAssignmentID, testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntime, model.DeletingAssignmentState, testValidConfig) 63 // faWithSourceAppAndTargetRuntimeForUnassingOpWithDeleteErrorState := fixFormationAssignmentModelWithStateAndConfig(testFormationAssignmentID, testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntime, model.DeletingAssignmentState, "") 64 // 65 // faWithSameSourceAppAndTarget := fixFormationAssignmentModelWithStateAndConfig(testFormationAssignmentID, testFormationID, internalTntID, faSourceID, faSourceID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeApplication, model.ReadyAssignmentState, "") 66 // 67 // testFormationAssignmentsForObject := []*model.FormationAssignment{ 68 // { 69 // ID: "ID1", 70 // }, 71 // { 72 // ID: "ID2", 73 // }, 74 // } 75 // 76 // emptyFormationAssignmentsForObject := []*model.FormationAssignment{} 77 // 78 // testFormationWithReadyState := fixFormationWithState(model.ReadyFormationState) 79 // testFormationWithInitialState := fixFormationWithState(model.InitialFormationState) 80 // 81 // testCases := []struct { 82 // name string 83 // transactFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) 84 // faServiceFn func() *automock.FormationAssignmentService 85 // faNotificationSvcFn func() *automock.FormationAssignmentNotificationService 86 // formationSvcFn func() *automock.FormationService 87 // faStatusSvcFn func() *automock.FormationAssignmentStatusService 88 // reqBody fm.FormationAssignmentRequestBody 89 // hasURLVars bool 90 // headers map[string][]string 91 // expectedStatusCode int 92 // expectedErrOutput string 93 // }{ 94 // // Request(+metadata) validation checks 95 // { 96 // name: "Decode Error: Content-Type header is not application/json", 97 // headers: map[string][]string{httputils.HeaderContentTypeKey: {"invalidContentType"}}, 98 // expectedStatusCode: http.StatusUnsupportedMediaType, 99 // expectedErrOutput: "Content-Type header is not application/json", 100 // }, 101 // { 102 // name: "Error when one or more of the required path parameters are missing", 103 // reqBody: fm.FormationAssignmentRequestBody{ 104 // State: model.ReadyAssignmentState, 105 // Configuration: json.RawMessage(testValidConfig), 106 // }, 107 // expectedStatusCode: http.StatusBadRequest, 108 // expectedErrOutput: "Not all of the required parameters are provided", 109 // }, 110 // // Request body validation checks 111 // { 112 // name: "Validate Error: error when we have ready state with config but also an error provided", 113 // reqBody: fm.FormationAssignmentRequestBody{ 114 // State: model.ReadyAssignmentState, 115 // Configuration: json.RawMessage(testValidConfig), 116 // Error: configurationErr.Error(), 117 // }, 118 // expectedStatusCode: http.StatusBadRequest, 119 // expectedErrOutput: "Request Body contains invalid input:", 120 // }, 121 // { 122 // name: "Validate Error: error when configuration is provided but the state is incorrect", 123 // reqBody: fm.FormationAssignmentRequestBody{ 124 // State: model.CreateErrorAssignmentState, 125 // Configuration: json.RawMessage(testValidConfig), 126 // }, 127 // expectedStatusCode: http.StatusBadRequest, 128 // expectedErrOutput: "Request Body contains invalid input:", 129 // }, 130 // // Business logic unit tests for assign operation 131 // { 132 // name: "Success when operation is assign", 133 // transactFn: txGen.ThatSucceeds, 134 // faServiceFn: func() *automock.FormationAssignmentService { 135 // faSvc := &automock.FormationAssignmentService{} 136 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 137 // faSvc.On("GetReverseBySourceAndTarget", contextThatHasTenant(internalTntID), testFormationID, faSourceID, faTargetID).Return(reverseFAWithSourceRuntimeAndTargetApp, nil).Once() 138 // faSvc.On("ProcessFormationAssignmentPair", contextThatHasTenant(internalTntID), testAssignmentPair).Return(false, nil).Once() 139 // return faSvc 140 // }, 141 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 142 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 143 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(fixEmptyNotificationRequest(), nil).Once() 144 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), reverseFAWithSourceRuntimeAndTargetApp).Return(fixEmptyNotificationRequest(), nil).Once() 145 // return faNotificationSvc 146 // }, 147 // formationSvcFn: func() *automock.FormationService { 148 // formationSvc := &automock.FormationService{} 149 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 150 // return formationSvc 151 // }, 152 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 153 // updater := &automock.FormationAssignmentStatusService{} 154 // updater.On("UpdateWithConstraints", txtest.CtxWithDBMatcher(), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 155 // return updater 156 // }, 157 // reqBody: fm.FormationAssignmentRequestBody{ 158 // State: model.ReadyAssignmentState, 159 // Configuration: json.RawMessage(testValidConfig), 160 // }, 161 // hasURLVars: true, 162 // expectedStatusCode: http.StatusOK, 163 // expectedErrOutput: "", 164 // }, 165 // { 166 // name: "Success when state is not changed - only configuration is provided", 167 // transactFn: txGen.ThatSucceeds, 168 // faServiceFn: func() *automock.FormationAssignmentService { 169 // faSvc := &automock.FormationAssignmentService{} 170 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 171 // faSvc.On("GetReverseBySourceAndTarget", contextThatHasTenant(internalTntID), testFormationID, faSourceID, faTargetID).Return(reverseFAWithSourceRuntimeAndTargetApp, nil).Once() 172 // faSvc.On("ProcessFormationAssignmentPair", contextThatHasTenant(internalTntID), testAssignmentPair).Return(false, nil).Once() 173 // return faSvc 174 // }, 175 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 176 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 177 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(fixEmptyNotificationRequest(), nil).Once() 178 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), reverseFAWithSourceRuntimeAndTargetApp).Return(fixEmptyNotificationRequest(), nil).Once() 179 // return faNotificationSvc 180 // }, 181 // formationSvcFn: func() *automock.FormationService { 182 // formationSvc := &automock.FormationService{} 183 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithInitialState, nil).Once() 184 // return formationSvc 185 // }, 186 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 187 // updater := &automock.FormationAssignmentStatusService{} 188 // updater.On("UpdateWithConstraints", txtest.CtxWithDBMatcher(), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 189 // return updater 190 // }, 191 // reqBody: fm.FormationAssignmentRequestBody{ 192 // Configuration: json.RawMessage(testValidConfig), 193 // }, 194 // hasURLVars: true, 195 // expectedStatusCode: http.StatusOK, 196 // expectedErrOutput: "", 197 // }, 198 // { 199 // name: "Error when transaction fails to begin", 200 // transactFn: txGen.ThatFailsOnBegin, 201 // reqBody: fm.FormationAssignmentRequestBody{ 202 // State: model.ReadyAssignmentState, 203 // Configuration: json.RawMessage(testValidConfig), 204 // }, 205 // hasURLVars: true, 206 // expectedStatusCode: http.StatusInternalServerError, 207 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 208 // }, 209 // { 210 // name: "Error when getting formation assignment globally", 211 // transactFn: txGen.ThatDoesntExpectCommit, 212 // faServiceFn: func() *automock.FormationAssignmentService { 213 // faSvc := &automock.FormationAssignmentService{} 214 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(nil, testErr).Once() 215 // return faSvc 216 // }, 217 // reqBody: fm.FormationAssignmentRequestBody{ 218 // State: model.ReadyAssignmentState, 219 // Configuration: json.RawMessage(testValidConfig), 220 // }, 221 // hasURLVars: true, 222 // expectedStatusCode: http.StatusInternalServerError, 223 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 224 // }, 225 // { 226 // name: "Error when getting formation by formation ID fail", 227 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 228 // return txGen.ThatDoesntExpectCommit() 229 // }, 230 // faServiceFn: func() *automock.FormationAssignmentService { 231 // faSvc := &automock.FormationAssignmentService{} 232 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 233 // return faSvc 234 // }, 235 // formationSvcFn: func() *automock.FormationService { 236 // formationSvc := &automock.FormationService{} 237 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(nil, testErr).Once() 238 // return formationSvc 239 // }, 240 // reqBody: fm.FormationAssignmentRequestBody{ 241 // State: model.ReadyAssignmentState, 242 // Configuration: json.RawMessage(testValidConfig), 243 // }, 244 // hasURLVars: true, 245 // expectedStatusCode: http.StatusInternalServerError, 246 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 247 // }, 248 // { 249 // name: "Error when the retrieved formation is not in READY state", 250 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 251 // return txGen.ThatDoesntExpectCommit() 252 // }, 253 // faServiceFn: func() *automock.FormationAssignmentService { 254 // faSvc := &automock.FormationAssignmentService{} 255 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 256 // return faSvc 257 // }, 258 // formationSvcFn: func() *automock.FormationService { 259 // formationSvc := &automock.FormationService{} 260 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithInitialState, nil).Once() 261 // return formationSvc 262 // }, 263 // reqBody: fm.FormationAssignmentRequestBody{ 264 // State: model.ReadyAssignmentState, 265 // Configuration: json.RawMessage(testValidConfig), 266 // }, 267 // hasURLVars: true, 268 // expectedStatusCode: http.StatusBadRequest, 269 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 270 // }, 271 // { 272 // name: "Error when request body state is not correct", 273 // transactFn: txGen.ThatDoesntExpectCommit, 274 // faServiceFn: func() *automock.FormationAssignmentService { 275 // faSvc := &automock.FormationAssignmentService{} 276 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 277 // return faSvc 278 // }, 279 // formationSvcFn: func() *automock.FormationService { 280 // formationSvc := &automock.FormationService{} 281 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 282 // return formationSvc 283 // }, 284 // reqBody: fm.FormationAssignmentRequestBody{ 285 // State: model.DeleteErrorAssignmentState, 286 // Error: configurationErr.Error(), 287 // }, 288 // hasURLVars: true, 289 // expectedStatusCode: http.StatusBadRequest, 290 // expectedErrOutput: fmt.Sprintf("An invalid state: %s is provided for %s operation", model.DeleteErrorAssignmentState, model.AssignFormation), 291 // }, 292 // { 293 // name: "Error when fail to set the formation assignment to error state", 294 // transactFn: txGen.ThatDoesntExpectCommit, 295 // faServiceFn: func() *automock.FormationAssignmentService { 296 // faSvc := &automock.FormationAssignmentService{} 297 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 298 // return faSvc 299 // }, 300 // formationSvcFn: func() *automock.FormationService { 301 // formationSvc := &automock.FormationService{} 302 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 303 // return formationSvc 304 // }, 305 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 306 // updater := &automock.FormationAssignmentStatusService{} 307 // updater.On("SetAssignmentToErrorStateWithConstraints", txtest.CtxWithDBMatcher(), faWithSourceAppAndTargetRuntime, configurationErr.Error(), formationassignment.AssignmentErrorCode(2), model.CreateErrorAssignmentState, model.CreateFormation).Return(testErr).Once() 308 // return updater 309 // }, 310 // reqBody: fm.FormationAssignmentRequestBody{ 311 // State: model.CreateErrorAssignmentState, 312 // Error: configurationErr.Error(), 313 // }, 314 // hasURLVars: true, 315 // expectedStatusCode: http.StatusInternalServerError, 316 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 317 // }, 318 // { 319 // name: "Successfully update formation assignment when input state is create error", 320 // transactFn: txGen.ThatSucceeds, 321 // faServiceFn: func() *automock.FormationAssignmentService { 322 // faSvc := &automock.FormationAssignmentService{} 323 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeWithCreateErrorState, nil).Once() 324 // return faSvc 325 // }, 326 // formationSvcFn: func() *automock.FormationService { 327 // formationSvc := &automock.FormationService{} 328 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 329 // return formationSvc 330 // }, 331 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 332 // updater := &automock.FormationAssignmentStatusService{} 333 // updater.On("SetAssignmentToErrorStateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeWithCreateErrorState, configurationErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.CreateErrorAssignmentState, model.CreateFormation).Return(nil).Once() 334 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeWithCreateErrorState, model.AssignFormation).Return(nil).Once() 335 // return updater 336 // }, 337 // reqBody: fm.FormationAssignmentRequestBody{ 338 // State: model.CreateErrorAssignmentState, 339 // Error: configurationErr.Error(), 340 // }, 341 // hasURLVars: true, 342 // expectedStatusCode: http.StatusOK, 343 // expectedErrOutput: "", 344 // }, 345 // { 346 // name: "Error when transaction fail to commit after successful formation assignment update", 347 // transactFn: txGen.ThatFailsOnCommit, 348 // faServiceFn: func() *automock.FormationAssignmentService { 349 // faSvc := &automock.FormationAssignmentService{} 350 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeWithCreateErrorState, nil).Once() 351 // return faSvc 352 // }, 353 // formationSvcFn: func() *automock.FormationService { 354 // formationSvc := &automock.FormationService{} 355 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 356 // return formationSvc 357 // }, 358 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 359 // updater := &automock.FormationAssignmentStatusService{} 360 // updater.On("SetAssignmentToErrorStateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeWithCreateErrorState, configurationErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.CreateErrorAssignmentState, model.CreateFormation).Return(nil).Once() 361 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeWithCreateErrorState, model.AssignFormation).Return(nil).Once() 362 // return updater 363 // }, 364 // reqBody: fm.FormationAssignmentRequestBody{ 365 // State: model.CreateErrorAssignmentState, 366 // Error: configurationErr.Error(), 367 // }, 368 // hasURLVars: true, 369 // expectedStatusCode: http.StatusInternalServerError, 370 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 371 // }, 372 // { 373 // name: "Error when setting formation assignment state to error fail", 374 // transactFn: txGen.ThatDoesntExpectCommit, 375 // faServiceFn: func() *automock.FormationAssignmentService { 376 // faSvc := &automock.FormationAssignmentService{} 377 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeWithCreateErrorState, nil).Once() 378 // return faSvc 379 // }, 380 // formationSvcFn: func() *automock.FormationService { 381 // formationSvc := &automock.FormationService{} 382 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 383 // return formationSvc 384 // }, 385 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 386 // updater := &automock.FormationAssignmentStatusService{} 387 // updater.On("SetAssignmentToErrorStateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeWithCreateErrorState, configurationErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.CreateErrorAssignmentState, model.CreateFormation).Return(nil).Once() 388 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeWithCreateErrorState, model.AssignFormation).Return(testErr).Once() 389 // return updater 390 // }, 391 // reqBody: fm.FormationAssignmentRequestBody{ 392 // State: model.CreateErrorAssignmentState, 393 // Error: configurationErr.Error(), 394 // }, 395 // hasURLVars: true, 396 // expectedStatusCode: http.StatusInternalServerError, 397 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 398 // }, 399 // { 400 // name: "Error when generating notifications for assignment fail", 401 // transactFn: txGen.ThatDoesntExpectCommit, 402 // faServiceFn: func() *automock.FormationAssignmentService { 403 // faSvc := &automock.FormationAssignmentService{} 404 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 405 // return faSvc 406 // }, 407 // formationSvcFn: func() *automock.FormationService { 408 // formationSvc := &automock.FormationService{} 409 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 410 // return formationSvc 411 // }, 412 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 413 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 414 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(nil, testErr).Once() 415 // return faNotificationSvc 416 // }, 417 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 418 // updater := &automock.FormationAssignmentStatusService{} 419 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 420 // return updater 421 // }, 422 // reqBody: fm.FormationAssignmentRequestBody{ 423 // State: model.ReadyAssignmentState, 424 // Configuration: json.RawMessage(testValidConfig), 425 // }, 426 // hasURLVars: true, 427 // expectedStatusCode: http.StatusInternalServerError, 428 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 429 // }, 430 // { 431 // name: "Error when getting reverse formation assignment fail", 432 // transactFn: txGen.ThatDoesntExpectCommit, 433 // faServiceFn: func() *automock.FormationAssignmentService { 434 // faSvc := &automock.FormationAssignmentService{} 435 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 436 // faSvc.On("GetReverseBySourceAndTarget", contextThatHasTenant(internalTntID), testFormationID, faSourceID, faTargetID).Return(nil, testErr).Once() 437 // return faSvc 438 // }, 439 // formationSvcFn: func() *automock.FormationService { 440 // formationSvc := &automock.FormationService{} 441 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 442 // return formationSvc 443 // }, 444 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 445 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 446 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(fixEmptyNotificationRequest(), nil).Once() 447 // return faNotificationSvc 448 // }, 449 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 450 // updater := &automock.FormationAssignmentStatusService{} 451 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 452 // return updater 453 // }, 454 // reqBody: fm.FormationAssignmentRequestBody{ 455 // State: model.ReadyAssignmentState, 456 // Configuration: json.RawMessage(testValidConfig), 457 // }, 458 // hasURLVars: true, 459 // expectedStatusCode: http.StatusInternalServerError, 460 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 461 // }, 462 // { 463 // name: "Error when generating reverse notifications for assignment fail", 464 // transactFn: txGen.ThatDoesntExpectCommit, 465 // faServiceFn: func() *automock.FormationAssignmentService { 466 // faSvc := &automock.FormationAssignmentService{} 467 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 468 // faSvc.On("GetReverseBySourceAndTarget", contextThatHasTenant(internalTntID), testFormationID, faSourceID, faTargetID).Return(reverseFAWithSourceRuntimeAndTargetApp, nil).Once() 469 // return faSvc 470 // }, 471 // formationSvcFn: func() *automock.FormationService { 472 // formationSvc := &automock.FormationService{} 473 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 474 // return formationSvc 475 // }, 476 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 477 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 478 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(fixEmptyNotificationRequest(), nil).Once() 479 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), reverseFAWithSourceRuntimeAndTargetApp).Return(nil, testErr).Once() 480 // return faNotificationSvc 481 // }, 482 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 483 // updater := &automock.FormationAssignmentStatusService{} 484 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 485 // return updater 486 // }, 487 // reqBody: fm.FormationAssignmentRequestBody{ 488 // State: model.ReadyAssignmentState, 489 // Configuration: json.RawMessage(testValidConfig), 490 // }, 491 // hasURLVars: true, 492 // expectedStatusCode: http.StatusInternalServerError, 493 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 494 // }, 495 // { 496 // name: "Error when processing formation assignment pairs", 497 // transactFn: txGen.ThatDoesntExpectCommit, 498 // faServiceFn: func() *automock.FormationAssignmentService { 499 // faSvc := &automock.FormationAssignmentService{} 500 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 501 // faSvc.On("GetReverseBySourceAndTarget", contextThatHasTenant(internalTntID), testFormationID, faSourceID, faTargetID).Return(reverseFAWithSourceRuntimeAndTargetApp, nil).Once() 502 // faSvc.On("ProcessFormationAssignmentPair", contextThatHasTenant(internalTntID), testAssignmentPair).Return(false, testErr).Once() 503 // return faSvc 504 // }, 505 // formationSvcFn: func() *automock.FormationService { 506 // formationSvc := &automock.FormationService{} 507 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 508 // return formationSvc 509 // }, 510 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 511 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 512 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(fixEmptyNotificationRequest(), nil).Once() 513 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), reverseFAWithSourceRuntimeAndTargetApp).Return(fixEmptyNotificationRequest(), nil).Once() 514 // return faNotificationSvc 515 // }, 516 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 517 // updater := &automock.FormationAssignmentStatusService{} 518 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 519 // return updater 520 // }, 521 // reqBody: fm.FormationAssignmentRequestBody{ 522 // State: model.ReadyAssignmentState, 523 // Configuration: json.RawMessage(testValidConfig), 524 // }, 525 // hasURLVars: true, 526 // expectedStatusCode: http.StatusInternalServerError, 527 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 528 // }, 529 // { 530 // name: "Error when committing transaction fail", 531 // transactFn: txGen.ThatFailsOnCommit, 532 // faServiceFn: func() *automock.FormationAssignmentService { 533 // faSvc := &automock.FormationAssignmentService{} 534 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil).Once() 535 // faSvc.On("GetReverseBySourceAndTarget", contextThatHasTenant(internalTntID), testFormationID, faSourceID, faTargetID).Return(reverseFAWithSourceRuntimeAndTargetApp, nil).Once() 536 // faSvc.On("ProcessFormationAssignmentPair", contextThatHasTenant(internalTntID), testAssignmentPair).Return(false, nil).Once() 537 // return faSvc 538 // }, 539 // formationSvcFn: func() *automock.FormationService { 540 // formationSvc := &automock.FormationService{} 541 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 542 // return formationSvc 543 // }, 544 // faNotificationSvcFn: func() *automock.FormationAssignmentNotificationService { 545 // faNotificationSvc := &automock.FormationAssignmentNotificationService{} 546 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime).Return(fixEmptyNotificationRequest(), nil).Once() 547 // faNotificationSvc.On("GenerateFormationAssignmentNotification", contextThatHasTenant(internalTntID), reverseFAWithSourceRuntimeAndTargetApp).Return(fixEmptyNotificationRequest(), nil).Once() 548 // return faNotificationSvc 549 // }, 550 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 551 // updater := &automock.FormationAssignmentStatusService{} 552 // updater.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntime, model.AssignFormation).Return(nil).Once() 553 // return updater 554 // }, 555 // reqBody: fm.FormationAssignmentRequestBody{ 556 // State: model.ReadyAssignmentState, 557 // Configuration: json.RawMessage(testValidConfig), 558 // }, 559 // hasURLVars: true, 560 // expectedStatusCode: http.StatusInternalServerError, 561 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 562 // }, 563 // // Business logic unit tests for unassign operation 564 // { 565 // name: "Success when operation is unassign", 566 // transactFn: txGen.ThatSucceedsTwice, 567 // faServiceFn: func() *automock.FormationAssignmentService { 568 // faSvc := &automock.FormationAssignmentService{} 569 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 570 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faSourceID).Return(testFormationAssignmentsForObject, nil).Once() 571 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faTargetID).Return(testFormationAssignmentsForObject, nil).Once() 572 // return faSvc 573 // }, 574 // formationSvcFn: func() *automock.FormationService { 575 // formationSvc := &automock.FormationService{} 576 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 577 // return formationSvc 578 // }, 579 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 580 // faStatusSvc := &automock.FormationAssignmentStatusService{} 581 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 582 // return faStatusSvc 583 // }, 584 // reqBody: fm.FormationAssignmentRequestBody{ 585 // State: model.ReadyAssignmentState, 586 // Configuration: json.RawMessage(testValidConfig), 587 // }, 588 // hasURLVars: true, 589 // expectedStatusCode: http.StatusOK, 590 // expectedErrOutput: "", 591 // }, 592 // { 593 // name: "Error when request body state is not correct", 594 // transactFn: txGen.ThatDoesntExpectCommit, 595 // faServiceFn: func() *automock.FormationAssignmentService { 596 // faSvc := &automock.FormationAssignmentService{} 597 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 598 // return faSvc 599 // }, 600 // reqBody: fm.FormationAssignmentRequestBody{ 601 // State: model.ConfigPendingAssignmentState, 602 // Configuration: json.RawMessage(testValidConfig), 603 // }, 604 // formationSvcFn: func() *automock.FormationService { 605 // formationSvc := &automock.FormationService{} 606 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 607 // return formationSvc 608 // }, 609 // hasURLVars: true, 610 // expectedStatusCode: http.StatusInternalServerError, 611 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 612 // }, 613 // { 614 // name: "Successfully set the formation assignment to error state", 615 // transactFn: txGen.ThatSucceeds, 616 // faServiceFn: func() *automock.FormationAssignmentService { 617 // faSvc := &automock.FormationAssignmentService{} 618 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOpWithDeleteErrorState, nil).Once() 619 // return faSvc 620 // }, 621 // reqBody: fm.FormationAssignmentRequestBody{ 622 // State: model.DeleteErrorAssignmentState, 623 // Error: configurationErr.Error(), 624 // }, 625 // formationSvcFn: func() *automock.FormationService { 626 // formationSvc := &automock.FormationService{} 627 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 628 // return formationSvc 629 // }, 630 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 631 // updater := &automock.FormationAssignmentStatusService{} 632 // updater.On("SetAssignmentToErrorStateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeForUnassingOpWithDeleteErrorState, configurationErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.DeleteErrorAssignmentState, model.UnassignFormation).Return(nil).Once() 633 // return updater 634 // }, 635 // hasURLVars: true, 636 // expectedStatusCode: http.StatusOK, 637 // expectedErrOutput: "", 638 // }, 639 // { 640 // name: "Error when setting formation assignment state to error fail", 641 // transactFn: txGen.ThatDoesntExpectCommit, 642 // faServiceFn: func() *automock.FormationAssignmentService { 643 // faSvc := &automock.FormationAssignmentService{} 644 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOpWithDeleteErrorState, nil).Once() 645 // return faSvc 646 // }, 647 // formationSvcFn: func() *automock.FormationService { 648 // formationSvc := &automock.FormationService{} 649 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 650 // return formationSvc 651 // }, 652 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 653 // updater := &automock.FormationAssignmentStatusService{} 654 // updater.On("SetAssignmentToErrorStateWithConstraints", contextThatHasTenant(internalTntID), faWithSourceAppAndTargetRuntimeForUnassingOpWithDeleteErrorState, configurationErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.DeleteErrorAssignmentState, model.UnassignFormation).Return(testErr).Once() 655 // return updater 656 // }, 657 // reqBody: fm.FormationAssignmentRequestBody{ 658 // State: model.DeleteErrorAssignmentState, 659 // Error: configurationErr.Error(), 660 // }, 661 // hasURLVars: true, 662 // expectedStatusCode: http.StatusInternalServerError, 663 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 664 // }, 665 // { 666 // name: "Error when deleting formation assignment fail", 667 // transactFn: txGen.ThatDoesntExpectCommit, 668 // faServiceFn: func() *automock.FormationAssignmentService { 669 // faSvc := &automock.FormationAssignmentService{} 670 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 671 // return faSvc 672 // }, 673 // reqBody: fm.FormationAssignmentRequestBody{ 674 // State: model.ReadyAssignmentState, 675 // Configuration: json.RawMessage(testValidConfig), 676 // }, 677 // formationSvcFn: func() *automock.FormationService { 678 // formationSvc := &automock.FormationService{} 679 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 680 // return formationSvc 681 // }, 682 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 683 // faStatusSvc := &automock.FormationAssignmentStatusService{} 684 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(testErr).Once() 685 // return faStatusSvc 686 // }, 687 // hasURLVars: true, 688 // expectedStatusCode: http.StatusInternalServerError, 689 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 690 // }, 691 // { 692 // name: "Error when listing formation assignments for object fail", 693 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 694 // return txGen.ThatSucceedsMultipleTimesAndCommitsMultipleTimes(2, 1) 695 // }, 696 // faServiceFn: func() *automock.FormationAssignmentService { 697 // faSvc := &automock.FormationAssignmentService{} 698 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 699 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faSourceID).Return(nil, testErr).Once() 700 // return faSvc 701 // }, 702 // formationSvcFn: func() *automock.FormationService { 703 // formationSvc := &automock.FormationService{} 704 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 705 // return formationSvc 706 // }, 707 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 708 // faStatusSvc := &automock.FormationAssignmentStatusService{} 709 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 710 // return faStatusSvc 711 // }, 712 // reqBody: fm.FormationAssignmentRequestBody{ 713 // State: model.ReadyAssignmentState, 714 // Configuration: json.RawMessage(testValidConfig), 715 // }, 716 // hasURLVars: true, 717 // expectedStatusCode: http.StatusInternalServerError, 718 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 719 // }, 720 // { 721 // name: "Successfully unassign formation when there are no formation assignment left", 722 // transactFn: txGen.ThatSucceedsTwice, 723 // faServiceFn: func() *automock.FormationAssignmentService { 724 // faSvc := &automock.FormationAssignmentService{} 725 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 726 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faSourceID).Return(emptyFormationAssignmentsForObject, nil).Once() 727 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faTargetID).Return(emptyFormationAssignmentsForObject, nil).Once() 728 // return faSvc 729 // }, 730 // formationSvcFn: func() *automock.FormationService { 731 // formationSvc := &automock.FormationService{} 732 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 733 // formationSvc.On("UnassignFormation", contextThatHasTenant(internalTntID), internalTntID, faSourceID, graphql.FormationObjectType(faWithSourceAppAndTargetRuntimeForUnassingOp.SourceType), *testFormationWithReadyState).Return(testFormationWithReadyState, nil).Once() 734 // formationSvc.On("UnassignFormation", contextThatHasTenant(internalTntID), internalTntID, faTargetID, graphql.FormationObjectType(faWithSourceAppAndTargetRuntimeForUnassingOp.TargetType), *testFormationWithReadyState).Return(testFormationWithReadyState, nil).Once() 735 // return formationSvc 736 // }, 737 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 738 // faStatusSvc := &automock.FormationAssignmentStatusService{} 739 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 740 // return faStatusSvc 741 // }, 742 // reqBody: fm.FormationAssignmentRequestBody{ 743 // State: model.ReadyAssignmentState, 744 // Configuration: json.RawMessage(testValidConfig), 745 // }, 746 // hasURLVars: true, 747 // expectedStatusCode: http.StatusOK, 748 // expectedErrOutput: "", 749 // }, 750 // { 751 // name: "Error when unassigning source from formation fail when there are no formation assignment left", 752 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 753 // return txGen.ThatSucceedsMultipleTimesAndCommitsMultipleTimes(2, 1) 754 // }, 755 // faServiceFn: func() *automock.FormationAssignmentService { 756 // faSvc := &automock.FormationAssignmentService{} 757 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 758 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faSourceID).Return(emptyFormationAssignmentsForObject, nil).Once() 759 // return faSvc 760 // }, 761 // formationSvcFn: func() *automock.FormationService { 762 // formationSvc := &automock.FormationService{} 763 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 764 // formationSvc.On("UnassignFormation", contextThatHasTenant(internalTntID), internalTntID, faSourceID, graphql.FormationObjectType(graphql.FormationAssignmentTypeApplication), *testFormationWithReadyState).Return(nil, testErr).Once() 765 // return formationSvc 766 // }, 767 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 768 // faStatusSvc := &automock.FormationAssignmentStatusService{} 769 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 770 // return faStatusSvc 771 // }, 772 // reqBody: fm.FormationAssignmentRequestBody{ 773 // State: model.ReadyAssignmentState, 774 // Configuration: json.RawMessage(testValidConfig), 775 // }, 776 // hasURLVars: true, 777 // expectedStatusCode: http.StatusInternalServerError, 778 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 779 // }, 780 // { 781 // name: "Error when trying to update formation assignment with same source and target", 782 // transactFn: txGen.ThatDoesntExpectCommit, 783 // faServiceFn: func() *automock.FormationAssignmentService { 784 // faSvc := &automock.FormationAssignmentService{} 785 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSameSourceAppAndTarget, nil).Once() 786 // return faSvc 787 // }, 788 // formationSvcFn: func() *automock.FormationService { 789 // formationSvc := &automock.FormationService{} 790 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 791 // return formationSvc 792 // }, 793 // reqBody: fm.FormationAssignmentRequestBody{ 794 // State: model.ReadyAssignmentState, 795 // Configuration: json.RawMessage(testValidConfig), 796 // }, 797 // hasURLVars: true, 798 // expectedStatusCode: http.StatusBadRequest, 799 // expectedErrOutput: "Cannot update formation assignment with source ", 800 // }, 801 // { 802 // name: "Error when unassigning target from formation fail when there are no formation assignment left", 803 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 804 // return txGen.ThatSucceedsMultipleTimesAndCommitsMultipleTimes(2, 1) 805 // }, 806 // faServiceFn: func() *automock.FormationAssignmentService { 807 // faSvc := &automock.FormationAssignmentService{} 808 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 809 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faSourceID).Return(emptyFormationAssignmentsForObject, nil).Once() 810 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faTargetID).Return(emptyFormationAssignmentsForObject, nil).Once() 811 // return faSvc 812 // }, 813 // formationSvcFn: func() *automock.FormationService { 814 // formationSvc := &automock.FormationService{} 815 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 816 // formationSvc.On("UnassignFormation", contextThatHasTenant(internalTntID), internalTntID, faSourceID, graphql.FormationObjectType(graphql.FormationAssignmentTypeApplication), *testFormationWithReadyState).Return(testFormationWithReadyState, nil).Once() 817 // formationSvc.On("UnassignFormation", contextThatHasTenant(internalTntID), internalTntID, faTargetID, graphql.FormationObjectType(graphql.FormationAssignmentTypeRuntime), *testFormationWithReadyState).Return(nil, testErr).Once() 818 // return formationSvc 819 // }, 820 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 821 // faStatusSvc := &automock.FormationAssignmentStatusService{} 822 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 823 // return faStatusSvc 824 // }, 825 // reqBody: fm.FormationAssignmentRequestBody{ 826 // State: model.ReadyAssignmentState, 827 // Configuration: json.RawMessage(testValidConfig), 828 // }, 829 // hasURLVars: true, 830 // expectedStatusCode: http.StatusInternalServerError, 831 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 832 // }, 833 // { 834 // name: "Error when transaction fail to commit", 835 // transactFn: txGen.ThatFailsOnCommit, 836 // faServiceFn: func() *automock.FormationAssignmentService { 837 // faSvc := &automock.FormationAssignmentService{} 838 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 839 // return faSvc 840 // }, 841 // formationSvcFn: func() *automock.FormationService { 842 // formationSvc := &automock.FormationService{} 843 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 844 // return formationSvc 845 // }, 846 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 847 // faStatusSvc := &automock.FormationAssignmentStatusService{} 848 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 849 // return faStatusSvc 850 // }, 851 // reqBody: fm.FormationAssignmentRequestBody{ 852 // State: model.ReadyAssignmentState, 853 // Configuration: json.RawMessage(testValidConfig), 854 // }, 855 // hasURLVars: true, 856 // expectedStatusCode: http.StatusInternalServerError, 857 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 858 // }, 859 // { 860 // name: "Error when second transaction fail on begin", 861 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 862 // persistTx := &persistenceautomock.PersistenceTx{} 863 // persistTx.On("Commit").Return(nil).Once() 864 // 865 // transact := &persistenceautomock.Transactioner{} 866 // transact.On("Begin").Return(persistTx, nil).Once() 867 // transact.On("Begin").Return(nil, testErr).Once() 868 // transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Once() 869 // 870 // return persistTx, transact 871 // }, 872 // faServiceFn: func() *automock.FormationAssignmentService { 873 // faSvc := &automock.FormationAssignmentService{} 874 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 875 // return faSvc 876 // }, 877 // formationSvcFn: func() *automock.FormationService { 878 // formationSvc := &automock.FormationService{} 879 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 880 // return formationSvc 881 // }, 882 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 883 // faStatusSvc := &automock.FormationAssignmentStatusService{} 884 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 885 // return faStatusSvc 886 // }, 887 // reqBody: fm.FormationAssignmentRequestBody{ 888 // State: model.ReadyAssignmentState, 889 // Configuration: json.RawMessage(testValidConfig), 890 // }, 891 // hasURLVars: true, 892 // expectedStatusCode: http.StatusInternalServerError, 893 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 894 // }, 895 // { 896 // name: "Error when second transaction fail to commit", 897 // transactFn: func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) { 898 // persistTx := &persistenceautomock.PersistenceTx{} 899 // persistTx.On("Commit").Return(nil).Once() 900 // persistTx.On("Commit").Return(testErr).Once() 901 // 902 // transact := &persistenceautomock.Transactioner{} 903 // transact.On("Begin").Return(persistTx, nil).Twice() 904 // transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Twice() 905 // 906 // return persistTx, transact 907 // }, 908 // faServiceFn: func() *automock.FormationAssignmentService { 909 // faSvc := &automock.FormationAssignmentService{} 910 // faSvc.On("GetGlobalByIDAndFormationID", txtest.CtxWithDBMatcher(), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeForUnassingOp, nil).Once() 911 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faSourceID).Return(testFormationAssignmentsForObject, nil).Once() 912 // faSvc.On("ListFormationAssignmentsForObjectID", contextThatHasTenant(internalTntID), testFormationID, faTargetID).Return(testFormationAssignmentsForObject, nil).Once() 913 // return faSvc 914 // }, 915 // formationSvcFn: func() *automock.FormationService { 916 // formationSvc := &automock.FormationService{} 917 // formationSvc.On("Get", txtest.CtxWithDBMatcher(), testFormationID).Return(testFormationWithReadyState, nil).Once() 918 // return formationSvc 919 // }, 920 // faStatusSvcFn: func() *automock.FormationAssignmentStatusService { 921 // faStatusSvc := &automock.FormationAssignmentStatusService{} 922 // faStatusSvc.On("DeleteWithConstraints", contextThatHasTenant(internalTntID), testFormationAssignmentID).Return(nil).Once() 923 // return faStatusSvc 924 // }, 925 // reqBody: fm.FormationAssignmentRequestBody{ 926 // State: model.ReadyAssignmentState, 927 // Configuration: json.RawMessage(testValidConfig), 928 // }, 929 // hasURLVars: true, 930 // expectedStatusCode: http.StatusInternalServerError, 931 // expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 932 // }, 933 // } 934 // 935 // for _, tCase := range testCases { 936 // t.Run(tCase.name, func(t *testing.T) { 937 // // GIVEN 938 // marshalBody, err := json.Marshal(tCase.reqBody) 939 // require.NoError(t, err) 940 // 941 // httpReq := httptest.NewRequest(http.MethodPatch, url, bytes.NewBuffer(marshalBody)) 942 // if tCase.hasURLVars { 943 // httpReq = mux.SetURLVars(httpReq, urlVars) 944 // } 945 // 946 // if tCase.headers != nil { 947 // httpReq.Header = tCase.headers 948 // } 949 // w := httptest.NewRecorder() 950 // 951 // persist, transact := fixUnusedTransactioner() 952 // if tCase.transactFn != nil { 953 // persist, transact = tCase.transactFn() 954 // } 955 // 956 // faSvc := fixUnusedFormationAssignmentSvc() 957 // if tCase.faServiceFn != nil { 958 // faSvc = tCase.faServiceFn() 959 // } 960 // 961 // faNotificationSvc := fixUnusedFormationAssignmentNotificationSvc() 962 // if tCase.faNotificationSvcFn != nil { 963 // faNotificationSvc = tCase.faNotificationSvcFn() 964 // } 965 // 966 // formationSvc := fixUnusedFormationSvc() 967 // if tCase.formationSvcFn != nil { 968 // formationSvc = tCase.formationSvcFn() 969 // } 970 // 971 // faStatusSvcFn := &automock.FormationAssignmentStatusService{} 972 // if tCase.faStatusSvcFn != nil { 973 // faStatusSvcFn = tCase.faStatusSvcFn() 974 // } 975 // 976 // defer mock.AssertExpectationsForObjects(t, persist, transact, faSvc, faNotificationSvc, formationSvc, faStatusSvcFn) 977 // 978 // handler := fm.NewFormationMappingHandler(transact, faSvc, faStatusSvcFn, faNotificationSvc, formationSvc, nil) 979 // 980 // // WHEN 981 // handler.UpdateFormationAssignmentStatus(w, httpReq) 982 // 983 // // THEN 984 // resp := w.Result() 985 // body, err := io.ReadAll(resp.Body) 986 // require.NoError(t, err) 987 // 988 // if tCase.expectedErrOutput == "" { 989 // require.NoError(t, err) 990 // } else { 991 // require.Contains(t, string(body), tCase.expectedErrOutput) 992 // } 993 // require.Equal(t, tCase.expectedStatusCode, resp.StatusCode) 994 // }) 995 // } 996 //} 997 998 func TestHandler_UpdateFormationStatus(t *testing.T) { 999 url := fmt.Sprintf("/v1/businessIntegrations/{%s}/status", fm.FormationIDParam) 1000 urlVars := map[string]string{ 1001 fm.FormationIDParam: testFormationID, 1002 } 1003 1004 formationWithInitialState := fixFormationWithState(model.InitialFormationState) 1005 formationWithReadyState := fixFormationWithState(model.ReadyFormationState) 1006 formationWithDeletingState := fixFormationWithState(model.DeletingFormationState) 1007 1008 testCases := []struct { 1009 name string 1010 transactFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) 1011 formationSvcFn func() *automock.FormationService 1012 faStatusSvcFn func() *automock.FormationAssignmentStatusService 1013 formationStatusSvcFn func() *automock.FormationStatusService 1014 reqBody fm.FormationRequestBody 1015 hasURLVars bool 1016 headers map[string][]string 1017 expectedStatusCode int 1018 expectedErrOutput string 1019 }{ 1020 // Request(+metadata) validation checks 1021 { 1022 name: "Decode Error: Content-Type header is not application/json", 1023 headers: map[string][]string{httputils.HeaderContentTypeKey: {"invalidContentType"}}, 1024 expectedStatusCode: http.StatusUnsupportedMediaType, 1025 expectedErrOutput: "Content-Type header is not application/json", 1026 }, 1027 { 1028 name: "Error when the required path parameter is missing", 1029 reqBody: fm.FormationRequestBody{ 1030 State: model.ReadyFormationState, 1031 }, 1032 expectedStatusCode: http.StatusBadRequest, 1033 expectedErrOutput: "Not all of the required parameters are provided", 1034 }, 1035 // Request body validation checks 1036 { 1037 name: "Validate Error: error when the state has unsupported value", 1038 reqBody: fm.FormationRequestBody{ 1039 State: "unsupported", 1040 }, 1041 expectedStatusCode: http.StatusBadRequest, 1042 expectedErrOutput: "Request Body contains invalid input:", 1043 }, 1044 { 1045 name: "Validate Error: error when we have an error with incorrect state", 1046 reqBody: fm.FormationRequestBody{ 1047 State: model.ReadyFormationState, 1048 Error: testErr.Error(), 1049 }, 1050 expectedStatusCode: http.StatusBadRequest, 1051 expectedErrOutput: "Request Body contains invalid input:", 1052 }, 1053 // Business logic unit tests 1054 { 1055 name: "Error when transaction fails to begin", 1056 transactFn: txGen.ThatFailsOnBegin, 1057 reqBody: fm.FormationRequestBody{ 1058 State: model.ReadyFormationState, 1059 }, 1060 hasURLVars: true, 1061 expectedStatusCode: http.StatusInternalServerError, 1062 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1063 }, 1064 { 1065 name: "Error when getting formation globally fails", 1066 transactFn: txGen.ThatDoesntExpectCommit, 1067 formationSvcFn: func() *automock.FormationService { 1068 formationSvc := &automock.FormationService{} 1069 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(nil, testErr).Once() 1070 return formationSvc 1071 }, 1072 reqBody: fm.FormationRequestBody{ 1073 State: model.ReadyFormationState, 1074 }, 1075 hasURLVars: true, 1076 expectedStatusCode: http.StatusInternalServerError, 1077 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1078 }, 1079 // Business logic unit tests for delete formation operation 1080 { 1081 name: "Successfully update formation status when operation is delete formation", 1082 transactFn: txGen.ThatSucceeds, 1083 formationSvcFn: func() *automock.FormationService { 1084 formationSvc := &automock.FormationService{} 1085 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithDeletingState, nil).Once() 1086 return formationSvc 1087 }, 1088 formationStatusSvcFn: func() *automock.FormationStatusService { 1089 formationStatusSvc := &automock.FormationStatusService{} 1090 formationStatusSvc.On("DeleteFormationEntityAndScenariosWithConstraints", contextThatHasTenant(internalTntID), internalTntID, formationWithDeletingState).Return(nil).Once() 1091 return formationStatusSvc 1092 }, 1093 reqBody: fm.FormationRequestBody{ 1094 State: model.ReadyFormationState, 1095 }, 1096 hasURLVars: true, 1097 expectedStatusCode: http.StatusOK, 1098 }, 1099 { 1100 name: "Successfully update formation status when operation is delete formation and state is DELETE_ERROR", 1101 transactFn: txGen.ThatSucceeds, 1102 formationSvcFn: func() *automock.FormationService { 1103 formationSvc := &automock.FormationService{} 1104 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithDeletingState, nil).Once() 1105 return formationSvc 1106 }, 1107 formationStatusSvcFn: func() *automock.FormationStatusService { 1108 formationStatusSvc := &automock.FormationStatusService{} 1109 formationStatusSvc.On("SetFormationToErrorStateWithConstraints", contextThatHasTenant(internalTntID), formationWithDeletingState, testErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.DeleteErrorFormationState, model.DeleteFormation).Return(nil).Once() 1110 return formationStatusSvc 1111 }, 1112 reqBody: fm.FormationRequestBody{ 1113 State: model.DeleteErrorFormationState, 1114 Error: testErr.Error(), 1115 }, 1116 hasURLVars: true, 1117 expectedStatusCode: http.StatusOK, 1118 }, 1119 { 1120 name: "Error when request body state is not correct for delete formation operation", 1121 transactFn: txGen.ThatDoesntExpectCommit, 1122 formationSvcFn: func() *automock.FormationService { 1123 formationSvc := &automock.FormationService{} 1124 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithDeletingState, nil).Once() 1125 return formationSvc 1126 }, 1127 reqBody: fm.FormationRequestBody{ 1128 State: model.CreateErrorFormationState, 1129 }, 1130 hasURLVars: true, 1131 expectedStatusCode: http.StatusInternalServerError, 1132 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1133 }, 1134 { 1135 name: "Error when updating the formation to delete error state fails", 1136 transactFn: txGen.ThatDoesntExpectCommit, 1137 formationSvcFn: func() *automock.FormationService { 1138 formationSvc := &automock.FormationService{} 1139 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithDeletingState, nil).Once() 1140 return formationSvc 1141 }, 1142 formationStatusSvcFn: func() *automock.FormationStatusService { 1143 formationStatusSvc := &automock.FormationStatusService{} 1144 formationStatusSvc.On("SetFormationToErrorStateWithConstraints", contextThatHasTenant(internalTntID), formationWithDeletingState, testErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.DeleteErrorFormationState, model.DeleteFormation).Return(testErr).Once() 1145 return formationStatusSvc 1146 }, 1147 reqBody: fm.FormationRequestBody{ 1148 State: model.DeleteErrorFormationState, 1149 Error: testErr.Error(), 1150 }, 1151 hasURLVars: true, 1152 expectedStatusCode: http.StatusInternalServerError, 1153 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1154 }, 1155 { 1156 name: "Error when deleting formation fails", 1157 transactFn: txGen.ThatDoesntExpectCommit, 1158 formationSvcFn: func() *automock.FormationService { 1159 formationSvc := &automock.FormationService{} 1160 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithDeletingState, nil).Once() 1161 return formationSvc 1162 }, 1163 formationStatusSvcFn: func() *automock.FormationStatusService { 1164 formationStatusSvc := &automock.FormationStatusService{} 1165 formationStatusSvc.On("DeleteFormationEntityAndScenariosWithConstraints", contextThatHasTenant(internalTntID), internalTntID, formationWithDeletingState).Return(testErr).Once() 1166 return formationStatusSvc 1167 }, 1168 reqBody: fm.FormationRequestBody{ 1169 State: model.ReadyFormationState, 1170 }, 1171 hasURLVars: true, 1172 expectedStatusCode: http.StatusInternalServerError, 1173 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1174 }, 1175 { 1176 name: "Error when transaction fails to commit after successful formation status update for delete operation", 1177 transactFn: txGen.ThatFailsOnCommit, 1178 formationSvcFn: func() *automock.FormationService { 1179 formationSvc := &automock.FormationService{} 1180 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithDeletingState, nil).Once() 1181 return formationSvc 1182 }, 1183 formationStatusSvcFn: func() *automock.FormationStatusService { 1184 formationStatusSvc := &automock.FormationStatusService{} 1185 formationStatusSvc.On("DeleteFormationEntityAndScenariosWithConstraints", contextThatHasTenant(internalTntID), internalTntID, formationWithDeletingState).Return(nil).Once() 1186 return formationStatusSvc 1187 }, 1188 reqBody: fm.FormationRequestBody{ 1189 State: model.ReadyFormationState, 1190 }, 1191 hasURLVars: true, 1192 expectedStatusCode: http.StatusInternalServerError, 1193 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1194 }, 1195 // Business logic unit tests for create formation operation 1196 { 1197 name: "Successfully update formation status when operation is create formation", 1198 transactFn: txGen.ThatSucceeds, 1199 formationSvcFn: func() *automock.FormationService { 1200 formationSvc := &automock.FormationService{} 1201 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1202 formationSvc.On("ResynchronizeFormationNotifications", contextThatHasTenant(internalTntID), testFormationID).Return(nil, nil).Once() 1203 return formationSvc 1204 }, 1205 formationStatusSvcFn: func() *automock.FormationStatusService { 1206 formationStatusSvc := &automock.FormationStatusService{} 1207 formationStatusSvc.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), formationWithReadyState, model.CreateFormation).Return(nil).Once() 1208 return formationStatusSvc 1209 }, 1210 reqBody: fm.FormationRequestBody{ 1211 State: model.ReadyFormationState, 1212 }, 1213 hasURLVars: true, 1214 expectedStatusCode: http.StatusOK, 1215 }, 1216 { 1217 name: "Successfully update formation status when operation is create formation and state is CREATE_ERROR", 1218 transactFn: txGen.ThatSucceeds, 1219 formationSvcFn: func() *automock.FormationService { 1220 formationSvc := &automock.FormationService{} 1221 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1222 return formationSvc 1223 }, 1224 formationStatusSvcFn: func() *automock.FormationStatusService { 1225 formationStatusSvc := &automock.FormationStatusService{} 1226 formationStatusSvc.On("SetFormationToErrorStateWithConstraints", contextThatHasTenant(internalTntID), formationWithInitialState, testErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.CreateErrorFormationState, model.CreateFormation).Return(nil).Once() 1227 return formationStatusSvc 1228 }, 1229 reqBody: fm.FormationRequestBody{ 1230 State: model.CreateErrorFormationState, 1231 Error: testErr.Error(), 1232 }, 1233 hasURLVars: true, 1234 expectedStatusCode: http.StatusOK, 1235 }, 1236 { 1237 name: "Error when request body state is not correct for create formation operation", 1238 transactFn: txGen.ThatDoesntExpectCommit, 1239 formationSvcFn: func() *automock.FormationService { 1240 formationSvc := &automock.FormationService{} 1241 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1242 return formationSvc 1243 }, 1244 reqBody: fm.FormationRequestBody{ 1245 State: model.DeleteErrorFormationState, 1246 }, 1247 hasURLVars: true, 1248 expectedStatusCode: http.StatusInternalServerError, 1249 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1250 }, 1251 { 1252 name: "Error when updating the formation to create error state fails", 1253 transactFn: txGen.ThatDoesntExpectCommit, 1254 formationSvcFn: func() *automock.FormationService { 1255 formationSvc := &automock.FormationService{} 1256 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1257 return formationSvc 1258 }, 1259 formationStatusSvcFn: func() *automock.FormationStatusService { 1260 formationStatusSvc := &automock.FormationStatusService{} 1261 formationStatusSvc.On("SetFormationToErrorStateWithConstraints", contextThatHasTenant(internalTntID), formationWithInitialState, testErr.Error(), formationassignment.AssignmentErrorCode(formationassignment.ClientError), model.CreateErrorFormationState, model.CreateFormation).Return(testErr).Once() 1262 return formationStatusSvc 1263 }, 1264 reqBody: fm.FormationRequestBody{ 1265 State: model.CreateErrorFormationState, 1266 Error: testErr.Error(), 1267 }, 1268 hasURLVars: true, 1269 expectedStatusCode: http.StatusInternalServerError, 1270 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1271 }, 1272 { 1273 name: "Error when updating the formation to ready state fails", 1274 transactFn: txGen.ThatDoesntExpectCommit, 1275 formationSvcFn: func() *automock.FormationService { 1276 formationSvc := &automock.FormationService{} 1277 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1278 return formationSvc 1279 }, 1280 formationStatusSvcFn: func() *automock.FormationStatusService { 1281 formationStatusSvc := &automock.FormationStatusService{} 1282 formationStatusSvc.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), formationWithReadyState, model.CreateFormation).Return(testErr).Once() 1283 return formationStatusSvc 1284 }, 1285 reqBody: fm.FormationRequestBody{ 1286 State: model.ReadyFormationState, 1287 }, 1288 hasURLVars: true, 1289 expectedStatusCode: http.StatusInternalServerError, 1290 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1291 }, 1292 { 1293 name: "Error when resynchronize formation notifications fails", 1294 transactFn: txGen.ThatDoesntExpectCommit, 1295 formationSvcFn: func() *automock.FormationService { 1296 formationSvc := &automock.FormationService{} 1297 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1298 formationSvc.On("ResynchronizeFormationNotifications", contextThatHasTenant(internalTntID), testFormationID).Return(nil, testErr).Once() 1299 return formationSvc 1300 }, 1301 formationStatusSvcFn: func() *automock.FormationStatusService { 1302 formationStatusSvc := &automock.FormationStatusService{} 1303 formationStatusSvc.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), formationWithReadyState, model.CreateFormation).Return(nil).Once() 1304 return formationStatusSvc 1305 }, 1306 reqBody: fm.FormationRequestBody{ 1307 State: model.ReadyFormationState, 1308 }, 1309 hasURLVars: true, 1310 expectedStatusCode: http.StatusInternalServerError, 1311 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1312 }, 1313 { 1314 name: "Error when transaction fails to commit after successful formation status update for create operation", 1315 transactFn: txGen.ThatFailsOnCommit, 1316 formationSvcFn: func() *automock.FormationService { 1317 formationSvc := &automock.FormationService{} 1318 formationSvc.On("GetGlobalByID", txtest.CtxWithDBMatcher(), testFormationID).Return(formationWithInitialState, nil).Once() 1319 formationSvc.On("ResynchronizeFormationNotifications", contextThatHasTenant(internalTntID), testFormationID).Return(nil, nil).Once() 1320 return formationSvc 1321 }, 1322 formationStatusSvcFn: func() *automock.FormationStatusService { 1323 formationStatusSvc := &automock.FormationStatusService{} 1324 formationStatusSvc.On("UpdateWithConstraints", contextThatHasTenant(internalTntID), formationWithReadyState, model.CreateFormation).Return(nil).Once() 1325 return formationStatusSvc 1326 }, 1327 reqBody: fm.FormationRequestBody{ 1328 State: model.ReadyFormationState, 1329 }, 1330 hasURLVars: true, 1331 expectedStatusCode: http.StatusInternalServerError, 1332 expectedErrOutput: "An unexpected error occurred while processing the request. X-Request-Id:", 1333 }, 1334 } 1335 1336 for _, tCase := range testCases { 1337 t.Run(tCase.name, func(t *testing.T) { 1338 // GIVEN 1339 marshalBody, err := json.Marshal(tCase.reqBody) 1340 require.NoError(t, err) 1341 1342 httpReq := httptest.NewRequest(http.MethodPatch, url, bytes.NewBuffer(marshalBody)) 1343 if tCase.hasURLVars { 1344 httpReq = mux.SetURLVars(httpReq, urlVars) 1345 } 1346 1347 if tCase.headers != nil { 1348 httpReq.Header = tCase.headers 1349 } 1350 w := httptest.NewRecorder() 1351 1352 persist, transact := fixUnusedTransactioner() 1353 if tCase.transactFn != nil { 1354 persist, transact = tCase.transactFn() 1355 } 1356 1357 formationSvc := fixUnusedFormationSvc() 1358 if tCase.formationSvcFn != nil { 1359 formationSvc = tCase.formationSvcFn() 1360 } 1361 1362 faUpdater := &automock.FormationAssignmentStatusService{} 1363 if tCase.faStatusSvcFn != nil { 1364 faUpdater = tCase.faStatusSvcFn() 1365 } 1366 1367 formationStatusSvc := &automock.FormationStatusService{} 1368 if tCase.formationStatusSvcFn != nil { 1369 formationStatusSvc = tCase.formationStatusSvcFn() 1370 } 1371 1372 defer mock.AssertExpectationsForObjects(t, persist, transact, formationSvc, faUpdater, formationStatusSvc) 1373 1374 handler := fm.NewFormationMappingHandler(transact, nil, faUpdater, nil, formationSvc, formationStatusSvc) 1375 1376 // WHEN 1377 handler.UpdateFormationStatus(w, httpReq) 1378 1379 // THEN 1380 resp := w.Result() 1381 body, err := io.ReadAll(resp.Body) 1382 require.NoError(t, err) 1383 1384 if tCase.expectedErrOutput == "" { 1385 require.NoError(t, err) 1386 } else { 1387 require.Contains(t, string(body), tCase.expectedErrOutput) 1388 } 1389 require.Equal(t, tCase.expectedStatusCode, resp.StatusCode) 1390 }) 1391 } 1392 }