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  }