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

     1  package formationassignment_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"testing"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/domain/formationassignment"
     9  	"github.com/kyma-incubator/compass/components/director/internal/domain/formationassignment/automock"
    10  	"github.com/kyma-incubator/compass/components/director/internal/model"
    11  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    12  	"github.com/kyma-incubator/compass/components/director/pkg/formationconstraint"
    13  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    14  	"github.com/stretchr/testify/mock"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestStatusService_UpdateWithConstraints(t *testing.T) {
    19  	preJoinPointDetails := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, fa, reverseFa, formationconstraint.PreNotificationStatusReturned)
    20  	postJoinPointDetails := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, fa, reverseFa, formationconstraint.PostNotificationStatusReturned)
    21  
    22  	// GIVEN
    23  	testCases := []struct {
    24  		Name                    string
    25  		Context                 context.Context
    26  		FormationAssignment     *model.FormationAssignment
    27  		FormationAssignmentRepo func() *automock.FormationAssignmentRepository
    28  		NotificationSvc         func() *automock.FaNotificationService
    29  		ConstraintEngine        func() *automock.ConstraintEngine
    30  		ExpectedErrorMsg        string
    31  	}{
    32  		{
    33  			Name:                "Success",
    34  			Context:             ctxWithTenant,
    35  			FormationAssignment: fa,
    36  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
    37  				repo := &automock.FormationAssignmentRepository{}
    38  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(true, nil).Once()
    39  				repo.On("Update", ctxWithTenant, fa).Return(nil).Once()
    40  				return repo
    41  			},
    42  			ConstraintEngine: func() *automock.ConstraintEngine {
    43  				constraintEngine := &automock.ConstraintEngine{}
    44  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
    45  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PostNotificationStatusReturned, postJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
    46  				return constraintEngine
    47  			},
    48  			NotificationSvc: func() *automock.FaNotificationService {
    49  				notificationSvc := &automock.FaNotificationService{}
    50  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
    51  				return notificationSvc
    52  			},
    53  		},
    54  		{
    55  			Name:                "Error when can't prepare details",
    56  			Context:             ctxWithTenant,
    57  			FormationAssignment: fa,
    58  			NotificationSvc: func() *automock.FaNotificationService {
    59  				notificationSvc := &automock.FaNotificationService{}
    60  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(nil, testErr).Once()
    61  				return notificationSvc
    62  			},
    63  			ExpectedErrorMsg: testErr.Error(),
    64  		},
    65  		{
    66  			Name:                "Error when enforcing PRE constraints",
    67  			Context:             ctxWithTenant,
    68  			FormationAssignment: fa,
    69  			ConstraintEngine: func() *automock.ConstraintEngine {
    70  				constraintEngine := &automock.ConstraintEngine{}
    71  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(testErr).Once()
    72  				return constraintEngine
    73  			},
    74  			NotificationSvc: func() *automock.FaNotificationService {
    75  				notificationSvc := &automock.FaNotificationService{}
    76  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
    77  				return notificationSvc
    78  			},
    79  			ExpectedErrorMsg: testErr.Error(),
    80  		},
    81  		{
    82  			Name:                "Error when checking for formation assignment existence",
    83  			Context:             ctxWithTenant,
    84  			FormationAssignment: fa,
    85  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
    86  				repo := &automock.FormationAssignmentRepository{}
    87  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(false, testErr).Once()
    88  				return repo
    89  			},
    90  			ConstraintEngine: func() *automock.ConstraintEngine {
    91  				constraintEngine := &automock.ConstraintEngine{}
    92  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
    93  				return constraintEngine
    94  			},
    95  			NotificationSvc: func() *automock.FaNotificationService {
    96  				notificationSvc := &automock.FaNotificationService{}
    97  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
    98  				return notificationSvc
    99  			},
   100  			ExpectedErrorMsg: testErr.Error(),
   101  		},
   102  		{
   103  			Name:                "Error when formation assignment does not exists",
   104  			Context:             ctxWithTenant,
   105  			FormationAssignment: fa,
   106  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   107  				repo := &automock.FormationAssignmentRepository{}
   108  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(false, nil).Once()
   109  				return repo
   110  			},
   111  			ConstraintEngine: func() *automock.ConstraintEngine {
   112  				constraintEngine := &automock.ConstraintEngine{}
   113  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   114  				return constraintEngine
   115  			},
   116  			NotificationSvc: func() *automock.FaNotificationService {
   117  				notificationSvc := &automock.FaNotificationService{}
   118  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
   119  				return notificationSvc
   120  			},
   121  			ExpectedErrorMsg: apperrors.NewNotFoundError(resource.FormationAssignment, fa.ID).Error(),
   122  		},
   123  		{
   124  			Name:                "Error when updating formation assignment",
   125  			Context:             ctxWithTenant,
   126  			FormationAssignment: fa,
   127  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   128  				repo := &automock.FormationAssignmentRepository{}
   129  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(true, nil).Once()
   130  				repo.On("Update", ctxWithTenant, fa).Return(testErr).Once()
   131  				return repo
   132  			},
   133  			ConstraintEngine: func() *automock.ConstraintEngine {
   134  				constraintEngine := &automock.ConstraintEngine{}
   135  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   136  				return constraintEngine
   137  			},
   138  			NotificationSvc: func() *automock.FaNotificationService {
   139  				notificationSvc := &automock.FaNotificationService{}
   140  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
   141  				return notificationSvc
   142  			},
   143  			ExpectedErrorMsg: testErr.Error(),
   144  		},
   145  		{
   146  			Name:                "Error when enforcing POST constraints",
   147  			Context:             ctxWithTenant,
   148  			FormationAssignment: fa,
   149  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   150  				repo := &automock.FormationAssignmentRepository{}
   151  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(true, nil).Once()
   152  				repo.On("Update", ctxWithTenant, fa).Return(nil).Once()
   153  				return repo
   154  			},
   155  			ConstraintEngine: func() *automock.ConstraintEngine {
   156  				constraintEngine := &automock.ConstraintEngine{}
   157  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   158  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PostNotificationStatusReturned, postJoinPointDetails, formation.FormationTemplateID).Return(testErr).Once()
   159  				return constraintEngine
   160  			},
   161  			NotificationSvc: func() *automock.FaNotificationService {
   162  				notificationSvc := &automock.FaNotificationService{}
   163  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
   164  				return notificationSvc
   165  			},
   166  			ExpectedErrorMsg: testErr.Error(),
   167  		},
   168  	}
   169  
   170  	for _, testCase := range testCases {
   171  		t.Run(testCase.Name, func(t *testing.T) {
   172  			faRepo := &automock.FormationAssignmentRepository{}
   173  			if testCase.FormationAssignmentRepo != nil {
   174  				faRepo = testCase.FormationAssignmentRepo()
   175  			}
   176  			constraintEngine := &automock.ConstraintEngine{}
   177  			if testCase.ConstraintEngine != nil {
   178  				constraintEngine = testCase.ConstraintEngine()
   179  			}
   180  			notificationSvc := &automock.FaNotificationService{}
   181  			if testCase.NotificationSvc != nil {
   182  				notificationSvc = testCase.NotificationSvc()
   183  			}
   184  
   185  			svc := formationassignment.NewFormationAssignmentStatusService(faRepo, constraintEngine, notificationSvc)
   186  
   187  			// WHEN
   188  			err := svc.UpdateWithConstraints(testCase.Context, testCase.FormationAssignment, assignOperation)
   189  
   190  			if testCase.ExpectedErrorMsg != "" {
   191  				require.Error(t, err)
   192  				require.Contains(t, err.Error(), testCase.ExpectedErrorMsg)
   193  			} else {
   194  				require.NoError(t, err)
   195  			}
   196  
   197  			mock.AssertExpectationsForObjects(t, faRepo, constraintEngine, notificationSvc)
   198  		})
   199  	}
   200  }
   201  
   202  func TestUpdater_SetAssignmentToErrorState(t *testing.T) {
   203  	errorMsg := "Test Error Message"
   204  
   205  	fa := &model.FormationAssignment{
   206  		ID:          TestID,
   207  		FormationID: TestFormationID,
   208  		TenantID:    TestTenantID,
   209  		Source:      TestSource,
   210  		SourceType:  TestSourceType,
   211  		Target:      TestTarget,
   212  		TargetType:  TestTargetType,
   213  		State:       TestStateInitial,
   214  		Value:       TestConfigValueRawJSON,
   215  	}
   216  
   217  	faErrorState := &model.FormationAssignment{
   218  		ID:          TestID,
   219  		FormationID: TestFormationID,
   220  		TenantID:    TestTenantID,
   221  		Source:      TestSource,
   222  		SourceType:  TestSourceType,
   223  		Target:      TestTarget,
   224  		TargetType:  TestTargetType,
   225  		State:       string(model.DeleteErrorFormationState),
   226  	}
   227  	assignmentError := formationassignment.AssignmentErrorWrapper{
   228  		Error: formationassignment.AssignmentError{
   229  			Message:   errorMsg,
   230  			ErrorCode: formationassignment.TechnicalError,
   231  		},
   232  	}
   233  	marshaled, err := json.Marshal(assignmentError)
   234  	require.NoError(t, err)
   235  	faErrorState.Value = marshaled
   236  
   237  	reverseFaErrorState := fixReverseFormationAssignment(faErrorState)
   238  
   239  	preJoinPointDetails := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, faErrorState, reverseFaErrorState, formationconstraint.PreNotificationStatusReturned)
   240  	postJoinPointDetails := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, faErrorState, reverseFaErrorState, formationconstraint.PostNotificationStatusReturned)
   241  
   242  	testCases := []struct {
   243  		Name                    string
   244  		Context                 context.Context
   245  		FormationAssignment     *model.FormationAssignment
   246  		FormationAssignmentRepo func() *automock.FormationAssignmentRepository
   247  		FormationRepo           func() *automock.FormationRepository
   248  		ConstraintEngine        func() *automock.ConstraintEngine
   249  		NotificationSvc         func() *automock.FaNotificationService
   250  		FormationOperation      model.FormationOperation
   251  		ExpectedErrorMsg        string
   252  	}{
   253  		{
   254  			Name:                "Success",
   255  			Context:             ctxWithTenant,
   256  			FormationAssignment: fa.Clone(),
   257  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   258  				repo := &automock.FormationAssignmentRepository{}
   259  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(true, nil).Once()
   260  				repo.On("Update", ctxWithTenant, faErrorState).Return(nil).Once()
   261  				return repo
   262  			},
   263  			ConstraintEngine: func() *automock.ConstraintEngine {
   264  				constraintEngine := &automock.ConstraintEngine{}
   265  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   266  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PostNotificationStatusReturned, postJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   267  				return constraintEngine
   268  			},
   269  			NotificationSvc: func() *automock.FaNotificationService {
   270  				notificationSvc := &automock.FaNotificationService{}
   271  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, faErrorState, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
   272  				return notificationSvc
   273  			},
   274  			FormationOperation: assignOperation,
   275  		},
   276  		{
   277  			Name:                "Returns error when updating fails",
   278  			Context:             ctxWithTenant,
   279  			FormationAssignment: fa.Clone(),
   280  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   281  				repo := &automock.FormationAssignmentRepository{}
   282  				repo.On("Exists", ctxWithTenant, TestID, TestTenantID).Return(true, nil).Once()
   283  				repo.On("Update", ctxWithTenant, faErrorState).Return(testErr).Once()
   284  				return repo
   285  			},
   286  			ConstraintEngine: func() *automock.ConstraintEngine {
   287  				constraintEngine := &automock.ConstraintEngine{}
   288  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   289  				return constraintEngine
   290  			},
   291  			NotificationSvc: func() *automock.FaNotificationService {
   292  				notificationSvc := &automock.FaNotificationService{}
   293  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, faErrorState, model.AssignFormation).Return(preJoinPointDetails, nil).Once()
   294  				return notificationSvc
   295  			},
   296  			FormationOperation: assignOperation,
   297  			ExpectedErrorMsg:   testErr.Error(),
   298  		},
   299  	}
   300  
   301  	for _, testCase := range testCases {
   302  		t.Run(testCase.Name, func(t *testing.T) {
   303  			faRepo := &automock.FormationAssignmentRepository{}
   304  			if testCase.FormationAssignmentRepo != nil {
   305  				faRepo = testCase.FormationAssignmentRepo()
   306  			}
   307  			constraintEngine := &automock.ConstraintEngine{}
   308  			if testCase.ConstraintEngine != nil {
   309  				constraintEngine = testCase.ConstraintEngine()
   310  			}
   311  			formationRepo := &automock.FormationRepository{}
   312  			if testCase.FormationRepo != nil {
   313  				formationRepo = testCase.FormationRepo()
   314  			}
   315  			notificationSvc := &automock.FaNotificationService{}
   316  			if testCase.NotificationSvc != nil {
   317  				notificationSvc = testCase.NotificationSvc()
   318  			}
   319  
   320  			svc := formationassignment.NewFormationAssignmentStatusService(faRepo, constraintEngine, notificationSvc)
   321  
   322  			// WHEN
   323  			err := svc.SetAssignmentToErrorStateWithConstraints(testCase.Context, testCase.FormationAssignment, errorMsg, formationassignment.TechnicalError, model.DeleteErrorAssignmentState, assignOperation)
   324  
   325  			if testCase.ExpectedErrorMsg != "" {
   326  				require.Error(t, err)
   327  				require.Contains(t, err.Error(), testCase.ExpectedErrorMsg)
   328  			} else {
   329  				require.NoError(t, err)
   330  			}
   331  
   332  			mock.AssertExpectationsForObjects(t, faRepo, constraintEngine, formationRepo, notificationSvc)
   333  		})
   334  	}
   335  }
   336  
   337  func TestStatusService_DeleteWithConstraints(t *testing.T) {
   338  	preJoinPointDetails := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, fa, reverseFa, formationconstraint.PreNotificationStatusReturned)
   339  	postJoinPointDetails := fixNotificationStatusReturnedDetails(model.ApplicationResourceType, appSubtype, fa, reverseFa, formationconstraint.PostNotificationStatusReturned)
   340  
   341  	// GIVEN
   342  	testCases := []struct {
   343  		Name                    string
   344  		Context                 context.Context
   345  		InputID                 string
   346  		FormationAssignmentRepo func() *automock.FormationAssignmentRepository
   347  		NotificationSvc         func() *automock.FaNotificationService
   348  		ConstraintEngine        func() *automock.ConstraintEngine
   349  		ExpectedErrorMsg        string
   350  	}{
   351  		{
   352  			Name:    "Success",
   353  			Context: ctxWithTenant,
   354  			InputID: TestID,
   355  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   356  				repo := &automock.FormationAssignmentRepository{}
   357  				repo.On("Get", ctxWithTenant, TestID, TestTenantID).Return(fa, nil).Once()
   358  				repo.On("Delete", ctxWithTenant, TestID, TestTenantID).Return(nil).Once()
   359  				return repo
   360  			},
   361  			ConstraintEngine: func() *automock.ConstraintEngine {
   362  				constraintEngine := &automock.ConstraintEngine{}
   363  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   364  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PostNotificationStatusReturned, postJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   365  				return constraintEngine
   366  			},
   367  			NotificationSvc: func() *automock.FaNotificationService {
   368  				notificationSvc := &automock.FaNotificationService{}
   369  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.UnassignFormation).Return(preJoinPointDetails, nil).Once()
   370  				return notificationSvc
   371  			},
   372  		},
   373  		{
   374  			Name:    "Returns error when can't enforce post constraints",
   375  			Context: ctxWithTenant,
   376  			InputID: TestID,
   377  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   378  				repo := &automock.FormationAssignmentRepository{}
   379  				repo.On("Get", ctxWithTenant, TestID, TestTenantID).Return(fa, nil).Once()
   380  				repo.On("Delete", ctxWithTenant, TestID, TestTenantID).Return(nil).Once()
   381  				return repo
   382  			},
   383  			ConstraintEngine: func() *automock.ConstraintEngine {
   384  				constraintEngine := &automock.ConstraintEngine{}
   385  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   386  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PostNotificationStatusReturned, postJoinPointDetails, formation.FormationTemplateID).Return(testErr).Once()
   387  				return constraintEngine
   388  			},
   389  			NotificationSvc: func() *automock.FaNotificationService {
   390  				notificationSvc := &automock.FaNotificationService{}
   391  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.UnassignFormation).Return(preJoinPointDetails, nil).Once()
   392  				return notificationSvc
   393  			},
   394  			ExpectedErrorMsg: testErr.Error(),
   395  		},
   396  		{
   397  			Name:    "Returns error when delete fails",
   398  			Context: ctxWithTenant,
   399  			InputID: TestID,
   400  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   401  				repo := &automock.FormationAssignmentRepository{}
   402  				repo.On("Get", ctxWithTenant, TestID, TestTenantID).Return(fa, nil).Once()
   403  				repo.On("Delete", ctxWithTenant, TestID, TestTenantID).Return(testErr).Once()
   404  				return repo
   405  			},
   406  			ConstraintEngine: func() *automock.ConstraintEngine {
   407  				constraintEngine := &automock.ConstraintEngine{}
   408  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(nil).Once()
   409  				return constraintEngine
   410  			},
   411  			NotificationSvc: func() *automock.FaNotificationService {
   412  				notificationSvc := &automock.FaNotificationService{}
   413  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.UnassignFormation).Return(preJoinPointDetails, nil).Once()
   414  				return notificationSvc
   415  			},
   416  			ExpectedErrorMsg: testErr.Error(),
   417  		},
   418  		{
   419  			Name:    "Returns error when can't enforce pre constraints",
   420  			Context: ctxWithTenant,
   421  			InputID: TestID,
   422  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   423  				repo := &automock.FormationAssignmentRepository{}
   424  				repo.On("Get", ctxWithTenant, TestID, TestTenantID).Return(fa, nil).Once()
   425  				return repo
   426  			},
   427  			ConstraintEngine: func() *automock.ConstraintEngine {
   428  				constraintEngine := &automock.ConstraintEngine{}
   429  				constraintEngine.On("EnforceConstraints", ctxWithTenant, formationconstraint.PreNotificationStatusReturned, preJoinPointDetails, formation.FormationTemplateID).Return(testErr).Once()
   430  				return constraintEngine
   431  			},
   432  			NotificationSvc: func() *automock.FaNotificationService {
   433  				notificationSvc := &automock.FaNotificationService{}
   434  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.UnassignFormation).Return(preJoinPointDetails, nil).Once()
   435  				return notificationSvc
   436  			},
   437  			ExpectedErrorMsg: testErr.Error(),
   438  		},
   439  		{
   440  			Name:    "Returns error when can't prepare details",
   441  			Context: ctxWithTenant,
   442  			InputID: TestID,
   443  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   444  				repo := &automock.FormationAssignmentRepository{}
   445  				repo.On("Get", ctxWithTenant, TestID, TestTenantID).Return(fa, nil).Once()
   446  				return repo
   447  			},
   448  			NotificationSvc: func() *automock.FaNotificationService {
   449  				notificationSvc := &automock.FaNotificationService{}
   450  				notificationSvc.On("PrepareDetailsForNotificationStatusReturned", ctxWithTenant, TestTenantID, fa, model.UnassignFormation).Return(nil, testErr).Once()
   451  				return notificationSvc
   452  			},
   453  			ExpectedErrorMsg: testErr.Error(),
   454  		},
   455  		{
   456  			Name:    "Returns error when can't get the formation assignment",
   457  			Context: ctxWithTenant,
   458  			InputID: TestID,
   459  			FormationAssignmentRepo: func() *automock.FormationAssignmentRepository {
   460  				repo := &automock.FormationAssignmentRepository{}
   461  				repo.On("Get", ctxWithTenant, TestID, TestTenantID).Return(nil, testErr).Once()
   462  				return repo
   463  			},
   464  			ExpectedErrorMsg: testErr.Error(),
   465  		},
   466  	}
   467  
   468  	for _, testCase := range testCases {
   469  		t.Run(testCase.Name, func(t *testing.T) {
   470  			faRepo := &automock.FormationAssignmentRepository{}
   471  			if testCase.FormationAssignmentRepo != nil {
   472  				faRepo = testCase.FormationAssignmentRepo()
   473  			}
   474  			constraintEngine := &automock.ConstraintEngine{}
   475  			if testCase.ConstraintEngine != nil {
   476  				constraintEngine = testCase.ConstraintEngine()
   477  			}
   478  			notificationSvc := &automock.FaNotificationService{}
   479  			if testCase.NotificationSvc != nil {
   480  				notificationSvc = testCase.NotificationSvc()
   481  			}
   482  
   483  			svc := formationassignment.NewFormationAssignmentStatusService(faRepo, constraintEngine, notificationSvc)
   484  
   485  			// WHEN
   486  			err := svc.DeleteWithConstraints(testCase.Context, testCase.InputID)
   487  
   488  			if testCase.ExpectedErrorMsg != "" {
   489  				require.Error(t, err)
   490  				require.Contains(t, err.Error(), testCase.ExpectedErrorMsg)
   491  			} else {
   492  				require.NoError(t, err)
   493  			}
   494  
   495  			mock.AssertExpectationsForObjects(t, faRepo, constraintEngine, notificationSvc)
   496  		})
   497  	}
   498  }