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

     1  package formationmapping_test
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"testing"
     8  
     9  	"github.com/google/uuid"
    10  	"github.com/gorilla/mux"
    11  	fm "github.com/kyma-incubator/compass/components/director/internal/formationmapping"
    12  	"github.com/kyma-incubator/compass/components/director/internal/formationmapping/automock"
    13  	"github.com/kyma-incubator/compass/components/director/internal/model"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/consumer"
    15  	persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock"
    16  	"github.com/stretchr/testify/mock"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestAuthenticator_FormationAssignmentHandler(t *testing.T) {
    21  	consumerUUID := uuid.New().String()
    22  	appTemplateID := "testAppTemplateID"
    23  	intSystemID := "intSystemID"
    24  	runtimeID := "testRuntimeID"
    25  
    26  	urlVars := map[string]string{
    27  		fm.FormationIDParam:           testFormationID,
    28  		fm.FormationAssignmentIDParam: testFormationAssignmentID,
    29  	}
    30  
    31  	faWithSourceAppAndTargetRuntime := fixFormationAssignmentModel(testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntime)
    32  	faWithSourceRuntimeAndTargetApp := fixFormationAssignmentModel(testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeRuntime, model.FormationAssignmentTypeApplication)
    33  	faWithSourceAppAndTargetRuntimeContext := fixFormationAssignmentModel(testFormationID, internalTntID, faSourceID, faTargetID, model.FormationAssignmentTypeApplication, model.FormationAssignmentTypeRuntimeContext)
    34  
    35  	intSysApp := &model.Application{
    36  		IntegrationSystemID: &intSystemID,
    37  	}
    38  
    39  	appWithAppTemplate := &model.Application{
    40  		ApplicationTemplateID: &appTemplateID,
    41  	}
    42  
    43  	consumerSubaccountLabelKey := "consumerSubaccountLabelKey"
    44  
    45  	appTemplateLbls := map[string]*model.Label{
    46  		consumerSubaccountLabelKey: {Key: consumerSubaccountLabelKey, Value: externalTntID},
    47  	}
    48  
    49  	appTemplateLblsWithInvalidConsumerSubaccount := map[string]*model.Label{
    50  		consumerSubaccountLabelKey: {Key: consumerSubaccountLabelKey, Value: "invalidConsumerSubaccountID"},
    51  	}
    52  
    53  	appTemplateLblsWithIncorrectType := map[string]*model.Label{
    54  		consumerSubaccountLabelKey: {Key: consumerSubaccountLabelKey, Value: model.FormationAssignmentTypeRuntime},
    55  	}
    56  
    57  	rtmContext := &model.RuntimeContext{
    58  		RuntimeID: runtimeID,
    59  	}
    60  
    61  	testCases := []struct {
    62  		name                       string
    63  		transactFn                 func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
    64  		faServiceFn                func() *automock.FormationAssignmentService
    65  		runtimeRepoFn              func() *automock.RuntimeRepository
    66  		runtimeContextRepoFn       func() *automock.RuntimeContextRepository
    67  		appRepoFn                  func() *automock.ApplicationRepository
    68  		appTemplateRepoFn          func() *automock.ApplicationTemplateRepository
    69  		labelRepoFn                func() *automock.LabelRepository
    70  		tenantRepoFn               func() *automock.TenantRepository
    71  		consumerSubaccountLabelKey string
    72  		hasURLVars                 bool
    73  		contextFn                  func() context.Context
    74  		httpMethod                 string
    75  		expectedStatusCode         int
    76  		expectedErrOutput          string
    77  	}{
    78  		// Common authorization checks
    79  		{
    80  			name:       "Error when the http request method is not PATCH",
    81  			transactFn: fixUnusedTransactioner,
    82  			contextFn: func() context.Context {
    83  				return emptyCtx
    84  			},
    85  			hasURLVars:         true,
    86  			httpMethod:         http.MethodGet,
    87  			expectedStatusCode: http.StatusMethodNotAllowed,
    88  			expectedErrOutput:  "",
    89  		},
    90  		{
    91  			name: "Error when required parameters are missing",
    92  			contextFn: func() context.Context {
    93  				return emptyCtx
    94  			},
    95  			expectedStatusCode: http.StatusBadRequest,
    96  			expectedErrOutput:  fixBuildExpectedErrResponse(t, "Not all of the required parameters are provided"),
    97  		},
    98  		{
    99  			name:       "Unauthorized error when authorization check is unsuccessful but there is no error",
   100  			transactFn: txGen.ThatSucceeds,
   101  			faServiceFn: func() *automock.FormationAssignmentService {
   102  				faSvc := &automock.FormationAssignmentService{}
   103  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(fixFormationAssignmentModel(testFormationID, internalTntID, faSourceID, faTargetID, "invalid", "invalid"), nil).Once()
   104  				return faSvc
   105  			},
   106  			contextFn: func() context.Context {
   107  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   108  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   109  			},
   110  			hasURLVars:         true,
   111  			expectedStatusCode: http.StatusUnauthorized,
   112  			expectedErrOutput:  "",
   113  		},
   114  		{
   115  			name: "Authorization fail: error when consumer info is missing in the context",
   116  			contextFn: func() context.Context {
   117  				return emptyCtx
   118  			},
   119  			hasURLVars:         true,
   120  			expectedStatusCode: http.StatusInternalServerError,
   121  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   122  		},
   123  		{
   124  			name:       "Authorization fail: error when transaction begin fails",
   125  			transactFn: txGen.ThatFailsOnBegin,
   126  			contextFn: func() context.Context {
   127  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   128  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   129  			},
   130  			hasURLVars:         true,
   131  			expectedStatusCode: http.StatusInternalServerError,
   132  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   133  		},
   134  		{
   135  			name:       "Authorization fail: error when getting formation assignment globally fails",
   136  			transactFn: txGen.ThatDoesntExpectCommit,
   137  			faServiceFn: func() *automock.FormationAssignmentService {
   138  				faSvc := &automock.FormationAssignmentService{}
   139  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(nil, testErr)
   140  				return faSvc
   141  			},
   142  			contextFn: func() context.Context {
   143  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   144  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   145  			},
   146  			hasURLVars:         true,
   147  			expectedStatusCode: http.StatusInternalServerError,
   148  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   149  		},
   150  		{
   151  			name:       "Authorization fail: error when tenant loading from context fails",
   152  			transactFn: txGen.ThatDoesntExpectCommit,
   153  			faServiceFn: func() *automock.FormationAssignmentService {
   154  				faSvc := &automock.FormationAssignmentService{}
   155  				faSvc.On("GetGlobalByIDAndFormationID", mock.Anything, testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil)
   156  				return faSvc
   157  			},
   158  			contextFn: func() context.Context {
   159  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   160  				ctxOnlyWithConsumer := consumer.SaveToContext(emptyCtx, c)
   161  				return ctxOnlyWithConsumer
   162  			},
   163  			hasURLVars:         true,
   164  			expectedStatusCode: http.StatusInternalServerError,
   165  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   166  		},
   167  		{
   168  			name:       "Authorization fail: error when committing transaction",
   169  			transactFn: txGen.ThatFailsOnCommit,
   170  			faServiceFn: func() *automock.FormationAssignmentService {
   171  				faSvc := &automock.FormationAssignmentService{}
   172  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(fixFormationAssignmentModel(testFormationID, internalTntID, faSourceID, faTargetID, "invalid", "invalid"), nil)
   173  				return faSvc
   174  			},
   175  			contextFn: func() context.Context {
   176  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   177  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   178  			},
   179  			hasURLVars:         true,
   180  			expectedStatusCode: http.StatusInternalServerError,
   181  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   182  		},
   183  		// Application/ApplicationTemplate authorization checks
   184  		{
   185  			name:       "Authorization fail: error when getting tenant",
   186  			transactFn: txGen.ThatDoesntExpectCommit,
   187  			faServiceFn: func() *automock.FormationAssignmentService {
   188  				faSvc := &automock.FormationAssignmentService{}
   189  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   190  				return faSvc
   191  			},
   192  			tenantRepoFn: func() *automock.TenantRepository {
   193  				tenantRepo := &automock.TenantRepository{}
   194  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(nil, testErr)
   195  				return tenantRepo
   196  			},
   197  			contextFn: func() context.Context {
   198  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   199  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   200  			},
   201  			hasURLVars:         true,
   202  			expectedStatusCode: http.StatusInternalServerError,
   203  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   204  		},
   205  		{
   206  			name:       "Authorization fail: error when getting application",
   207  			transactFn: txGen.ThatDoesntExpectCommit,
   208  			faServiceFn: func() *automock.FormationAssignmentService {
   209  				faSvc := &automock.FormationAssignmentService{}
   210  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   211  				return faSvc
   212  			},
   213  			tenantRepoFn: func() *automock.TenantRepository {
   214  				tenantRepo := &automock.TenantRepository{}
   215  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   216  				return tenantRepo
   217  			},
   218  			appRepoFn: func() *automock.ApplicationRepository {
   219  				appRepo := &automock.ApplicationRepository{}
   220  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(nil, testErr)
   221  				return appRepo
   222  			},
   223  			contextFn: func() context.Context {
   224  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   225  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   226  			},
   227  			hasURLVars:         true,
   228  			expectedStatusCode: http.StatusInternalServerError,
   229  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   230  		},
   231  		{
   232  			name:       "Authorization fail: error when application owner existence check fail",
   233  			transactFn: txGen.ThatDoesntExpectCommit,
   234  			faServiceFn: func() *automock.FormationAssignmentService {
   235  				faSvc := &automock.FormationAssignmentService{}
   236  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   237  				return faSvc
   238  			},
   239  			tenantRepoFn: func() *automock.TenantRepository {
   240  				tenantRepo := &automock.TenantRepository{}
   241  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   242  				return tenantRepo
   243  			},
   244  			appRepoFn: func() *automock.ApplicationRepository {
   245  				appRepo := &automock.ApplicationRepository{}
   246  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(intSysApp, nil)
   247  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, testErr)
   248  				return appRepo
   249  			},
   250  			contextFn: func() context.Context {
   251  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   252  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   253  			},
   254  			hasURLVars:         true,
   255  			expectedStatusCode: http.StatusInternalServerError,
   256  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   257  		},
   258  		{
   259  			name:       "Authorization fail: error when application template is nil or empty",
   260  			transactFn: txGen.ThatDoesntExpectCommit,
   261  			faServiceFn: func() *automock.FormationAssignmentService {
   262  				faSvc := &automock.FormationAssignmentService{}
   263  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   264  				return faSvc
   265  			},
   266  			tenantRepoFn: func() *automock.TenantRepository {
   267  				tenantRepo := &automock.TenantRepository{}
   268  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   269  				return tenantRepo
   270  			},
   271  			appRepoFn: func() *automock.ApplicationRepository {
   272  				appRepo := &automock.ApplicationRepository{}
   273  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(intSysApp, nil)
   274  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   275  				return appRepo
   276  			},
   277  			contextFn: func() context.Context {
   278  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   279  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   280  			},
   281  			hasURLVars:         true,
   282  			expectedStatusCode: http.StatusUnauthorized,
   283  			expectedErrOutput:  "",
   284  		},
   285  		{
   286  			name:       "Authorization fail: error when application template existence check fails",
   287  			transactFn: txGen.ThatDoesntExpectCommit,
   288  			faServiceFn: func() *automock.FormationAssignmentService {
   289  				faSvc := &automock.FormationAssignmentService{}
   290  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   291  				return faSvc
   292  			},
   293  			tenantRepoFn: func() *automock.TenantRepository {
   294  				tenantRepo := &automock.TenantRepository{}
   295  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   296  				return tenantRepo
   297  			},
   298  			appRepoFn: func() *automock.ApplicationRepository {
   299  				appRepo := &automock.ApplicationRepository{}
   300  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   301  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   302  				return appRepo
   303  			},
   304  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   305  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   306  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(false, testErr)
   307  				return appTemplateRepo
   308  			},
   309  			contextFn: func() context.Context {
   310  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   311  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   312  			},
   313  			hasURLVars:         true,
   314  			expectedStatusCode: http.StatusUnauthorized,
   315  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   316  		},
   317  		{
   318  			name:       "Authorization fail: error when application template does not exists",
   319  			transactFn: txGen.ThatDoesntExpectCommit,
   320  			faServiceFn: func() *automock.FormationAssignmentService {
   321  				faSvc := &automock.FormationAssignmentService{}
   322  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   323  				return faSvc
   324  			},
   325  			tenantRepoFn: func() *automock.TenantRepository {
   326  				tenantRepo := &automock.TenantRepository{}
   327  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   328  				return tenantRepo
   329  			},
   330  			appRepoFn: func() *automock.ApplicationRepository {
   331  				appRepo := &automock.ApplicationRepository{}
   332  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   333  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   334  				return appRepo
   335  			},
   336  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   337  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   338  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(false, nil)
   339  				return appTemplateRepo
   340  			},
   341  			contextFn: func() context.Context {
   342  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   343  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   344  			},
   345  			hasURLVars:         true,
   346  			expectedStatusCode: http.StatusUnauthorized,
   347  			expectedErrOutput:  "",
   348  		},
   349  		{
   350  			name:       "Authorization fail: error when listing application template labels",
   351  			transactFn: txGen.ThatDoesntExpectCommit,
   352  			faServiceFn: func() *automock.FormationAssignmentService {
   353  				faSvc := &automock.FormationAssignmentService{}
   354  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   355  				return faSvc
   356  			},
   357  			tenantRepoFn: func() *automock.TenantRepository {
   358  				tenantRepo := &automock.TenantRepository{}
   359  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   360  				return tenantRepo
   361  			},
   362  			appRepoFn: func() *automock.ApplicationRepository {
   363  				appRepo := &automock.ApplicationRepository{}
   364  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   365  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   366  				return appRepo
   367  			},
   368  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   369  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   370  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(true, nil)
   371  				return appTemplateRepo
   372  			},
   373  			labelRepoFn: func() *automock.LabelRepository {
   374  				lblRepo := &automock.LabelRepository{}
   375  				lblRepo.On("ListForGlobalObject", contextThatHasTenant(internalTntID), model.AppTemplateLabelableObject, appTemplateID).Return(nil, testErr)
   376  				return lblRepo
   377  			},
   378  			contextFn: func() context.Context {
   379  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   380  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   381  			},
   382  			hasURLVars:         true,
   383  			expectedStatusCode: http.StatusInternalServerError,
   384  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   385  		},
   386  		{
   387  			name:       "Authorization fail: error when listing application template labels doesn't include subaccount label",
   388  			transactFn: txGen.ThatDoesntExpectCommit,
   389  			faServiceFn: func() *automock.FormationAssignmentService {
   390  				faSvc := &automock.FormationAssignmentService{}
   391  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   392  				return faSvc
   393  			},
   394  			tenantRepoFn: func() *automock.TenantRepository {
   395  				tenantRepo := &automock.TenantRepository{}
   396  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   397  				return tenantRepo
   398  			},
   399  			appRepoFn: func() *automock.ApplicationRepository {
   400  				appRepo := &automock.ApplicationRepository{}
   401  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   402  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   403  				return appRepo
   404  			},
   405  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   406  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   407  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(true, nil)
   408  				return appTemplateRepo
   409  			},
   410  			labelRepoFn: func() *automock.LabelRepository {
   411  				lblRepo := &automock.LabelRepository{}
   412  				lblRepo.On("ListForGlobalObject", contextThatHasTenant(internalTntID), model.AppTemplateLabelableObject, appTemplateID).Return(map[string]*model.Label{}, nil)
   413  				return lblRepo
   414  			},
   415  			contextFn: func() context.Context {
   416  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   417  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   418  			},
   419  			hasURLVars:         true,
   420  			expectedStatusCode: http.StatusUnauthorized,
   421  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   422  		},
   423  		{
   424  			name:       "Authorization fail: error when consumer subaccount label is not of type string",
   425  			transactFn: txGen.ThatDoesntExpectCommit,
   426  			faServiceFn: func() *automock.FormationAssignmentService {
   427  				faSvc := &automock.FormationAssignmentService{}
   428  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   429  				return faSvc
   430  			},
   431  			tenantRepoFn: func() *automock.TenantRepository {
   432  				tenantRepo := &automock.TenantRepository{}
   433  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   434  				return tenantRepo
   435  			},
   436  			appRepoFn: func() *automock.ApplicationRepository {
   437  				appRepo := &automock.ApplicationRepository{}
   438  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   439  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   440  				return appRepo
   441  			},
   442  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   443  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   444  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(true, nil)
   445  				return appTemplateRepo
   446  			},
   447  			labelRepoFn: func() *automock.LabelRepository {
   448  				lblRepo := &automock.LabelRepository{}
   449  				lblRepo.On("ListForGlobalObject", contextThatHasTenant(internalTntID), model.AppTemplateLabelableObject, appTemplateID).Return(appTemplateLblsWithIncorrectType, nil)
   450  				return lblRepo
   451  			},
   452  			consumerSubaccountLabelKey: consumerSubaccountLabelKey,
   453  			contextFn: func() context.Context {
   454  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   455  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   456  			},
   457  			hasURLVars:         true,
   458  			expectedStatusCode: http.StatusUnauthorized,
   459  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   460  		},
   461  		{
   462  			name:       "Authorization fail: when caller has NOT owner access to the target FA with type app that is made through subscription",
   463  			transactFn: txGen.ThatDoesntExpectCommit,
   464  			faServiceFn: func() *automock.FormationAssignmentService {
   465  				faSvc := &automock.FormationAssignmentService{}
   466  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   467  				return faSvc
   468  			},
   469  			tenantRepoFn: func() *automock.TenantRepository {
   470  				tenantRepo := &automock.TenantRepository{}
   471  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   472  				return tenantRepo
   473  			},
   474  			appRepoFn: func() *automock.ApplicationRepository {
   475  				appRepo := &automock.ApplicationRepository{}
   476  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   477  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   478  				return appRepo
   479  			},
   480  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   481  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   482  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(true, nil)
   483  				return appTemplateRepo
   484  			},
   485  			labelRepoFn: func() *automock.LabelRepository {
   486  				lblRepo := &automock.LabelRepository{}
   487  				lblRepo.On("ListForGlobalObject", contextThatHasTenant(internalTntID), model.AppTemplateLabelableObject, appTemplateID).Return(appTemplateLblsWithInvalidConsumerSubaccount, nil)
   488  				return lblRepo
   489  			},
   490  			consumerSubaccountLabelKey: consumerSubaccountLabelKey,
   491  			contextFn: func() context.Context {
   492  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   493  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   494  			},
   495  			hasURLVars:         true,
   496  			expectedStatusCode: http.StatusUnauthorized,
   497  			expectedErrOutput:  "",
   498  		},
   499  		{
   500  			name:       "Authorization success: when the int system caller has owner access to the target formation assignment with type application",
   501  			transactFn: txGen.ThatSucceeds,
   502  			faServiceFn: func() *automock.FormationAssignmentService {
   503  				faSvc := &automock.FormationAssignmentService{}
   504  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(intSystemID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   505  				return faSvc
   506  			},
   507  			tenantRepoFn: func() *automock.TenantRepository {
   508  				tenantRepo := &automock.TenantRepository{}
   509  				tenantRepo.On("Get", contextThatHasConsumer(intSystemID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   510  				return tenantRepo
   511  			},
   512  			appRepoFn: func() *automock.ApplicationRepository {
   513  				appRepo := &automock.ApplicationRepository{}
   514  				appRepo.On("GetByID", contextThatHasConsumer(intSystemID), internalTntID, faTargetID).Return(intSysApp, nil)
   515  				return appRepo
   516  			},
   517  			contextFn: func() context.Context {
   518  				c := fixGetConsumer(intSystemID, consumer.IntegrationSystem)
   519  				return fixContextWithConsumer(c)
   520  			},
   521  			hasURLVars:         true,
   522  			expectedStatusCode: http.StatusOK,
   523  			expectedErrOutput:  "",
   524  		},
   525  		{
   526  			name:       "Authorization fail: when the int system caller manages the target FA with type application but the transaction fail",
   527  			transactFn: txGen.ThatFailsOnCommit,
   528  			faServiceFn: func() *automock.FormationAssignmentService {
   529  				faSvc := &automock.FormationAssignmentService{}
   530  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(intSystemID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   531  				return faSvc
   532  			},
   533  			tenantRepoFn: func() *automock.TenantRepository {
   534  				tenantRepo := &automock.TenantRepository{}
   535  				tenantRepo.On("Get", contextThatHasConsumer(intSystemID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   536  				return tenantRepo
   537  			},
   538  			appRepoFn: func() *automock.ApplicationRepository {
   539  				appRepo := &automock.ApplicationRepository{}
   540  				appRepo.On("GetByID", contextThatHasConsumer(intSystemID), internalTntID, faTargetID).Return(intSysApp, nil)
   541  				return appRepo
   542  			},
   543  			contextFn: func() context.Context {
   544  				c := fixGetConsumer(intSystemID, consumer.IntegrationSystem)
   545  				return fixContextWithConsumer(c)
   546  			},
   547  			hasURLVars:         true,
   548  			expectedStatusCode: http.StatusInternalServerError,
   549  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   550  		},
   551  		{
   552  			name:       "Authorization success: when caller is business integration and the formation is in a tenant of type resource group",
   553  			transactFn: txGen.ThatSucceeds,
   554  			faServiceFn: func() *automock.FormationAssignmentService {
   555  				faSvc := &automock.FormationAssignmentService{}
   556  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(consumerUUID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   557  				return faSvc
   558  			},
   559  			tenantRepoFn: func() *automock.TenantRepository {
   560  				tenantRepo := &automock.TenantRepository{}
   561  				tenantRepo.On("Get", contextThatHasConsumer(consumerUUID), internalTntID).Return(fixResourceGroupBusinessTenantMapping(), nil)
   562  				return tenantRepo
   563  			},
   564  			contextFn: func() context.Context {
   565  				c := fixGetConsumer(consumerUUID, consumer.BusinessIntegration)
   566  				return fixContextWithConsumer(c)
   567  			},
   568  			hasURLVars:         true,
   569  			expectedStatusCode: http.StatusOK,
   570  			expectedErrOutput:  "",
   571  		},
   572  		{
   573  			name:       "Authorization fail: when caller is business integration and the formation is in a tenant of type resource group but the transaction fail",
   574  			transactFn: txGen.ThatFailsOnCommit,
   575  			faServiceFn: func() *automock.FormationAssignmentService {
   576  				faSvc := &automock.FormationAssignmentService{}
   577  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(consumerUUID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   578  				return faSvc
   579  			},
   580  			tenantRepoFn: func() *automock.TenantRepository {
   581  				tenantRepo := &automock.TenantRepository{}
   582  				tenantRepo.On("Get", contextThatHasConsumer(consumerUUID), internalTntID).Return(fixResourceGroupBusinessTenantMapping(), nil)
   583  				return tenantRepo
   584  			},
   585  			contextFn: func() context.Context {
   586  				c := fixGetConsumer(consumerUUID, consumer.BusinessIntegration)
   587  				return fixContextWithConsumer(c)
   588  			},
   589  			hasURLVars:         true,
   590  			expectedStatusCode: http.StatusInternalServerError,
   591  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   592  		},
   593  		{
   594  			name:       "Authorization fail: when the caller is the parent of the formation assignment target with type application but the transaction fail",
   595  			transactFn: txGen.ThatFailsOnCommit,
   596  			faServiceFn: func() *automock.FormationAssignmentService {
   597  				faSvc := &automock.FormationAssignmentService{}
   598  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(appTemplateID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   599  				return faSvc
   600  			},
   601  			tenantRepoFn: func() *automock.TenantRepository {
   602  				tenantRepo := &automock.TenantRepository{}
   603  				tenantRepo.On("Get", contextThatHasConsumer(appTemplateID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   604  				return tenantRepo
   605  			},
   606  			appRepoFn: func() *automock.ApplicationRepository {
   607  				appRepo := &automock.ApplicationRepository{}
   608  				appRepo.On("GetByID", contextThatHasConsumer(appTemplateID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   609  				return appRepo
   610  			},
   611  			contextFn: func() context.Context {
   612  				c := fixGetConsumer(appTemplateID, consumer.ExternalCertificate)
   613  				return fixContextWithConsumer(c)
   614  			},
   615  			hasURLVars:         true,
   616  			expectedStatusCode: http.StatusInternalServerError,
   617  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   618  		},
   619  		{
   620  			name:       "Authorization success: when the caller is the parent of the formation assignment target with type application",
   621  			transactFn: txGen.ThatSucceeds,
   622  			faServiceFn: func() *automock.FormationAssignmentService {
   623  				faSvc := &automock.FormationAssignmentService{}
   624  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(appTemplateID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   625  				return faSvc
   626  			},
   627  			tenantRepoFn: func() *automock.TenantRepository {
   628  				tenantRepo := &automock.TenantRepository{}
   629  				tenantRepo.On("Get", contextThatHasConsumer(appTemplateID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   630  				return tenantRepo
   631  			},
   632  			appRepoFn: func() *automock.ApplicationRepository {
   633  				appRepo := &automock.ApplicationRepository{}
   634  				appRepo.On("GetByID", contextThatHasConsumer(appTemplateID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   635  				return appRepo
   636  			},
   637  			contextFn: func() context.Context {
   638  				c := fixGetConsumer(appTemplateID, consumer.ExternalCertificate)
   639  				return fixContextWithConsumer(c)
   640  			},
   641  			hasURLVars:         true,
   642  			expectedStatusCode: http.StatusOK,
   643  			expectedErrOutput:  "",
   644  		},
   645  		{
   646  			name:       "Authorization fail: error when consumer info is missing in the context for formation assignment with target type application",
   647  			transactFn: txGen.ThatDoesntExpectCommit,
   648  			faServiceFn: func() *automock.FormationAssignmentService {
   649  				faSvc := &automock.FormationAssignmentService{}
   650  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasConsumer(consumerUUID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   651  				return faSvc
   652  			},
   653  			tenantRepoFn: func() *automock.TenantRepository {
   654  				tenantRepo := &automock.TenantRepository{}
   655  				tenantRepo.On("Get", contextThatHasConsumer(consumerUUID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   656  				return tenantRepo
   657  			},
   658  			appRepoFn: func() *automock.ApplicationRepository {
   659  				appRepo := &automock.ApplicationRepository{}
   660  				appRepo.On("GetByID", contextThatHasConsumer(consumerUUID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   661  				return appRepo
   662  			},
   663  			contextFn: func() context.Context {
   664  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   665  				return fixContextWithConsumer(c)
   666  			},
   667  			hasURLVars:         true,
   668  			expectedStatusCode: http.StatusInternalServerError,
   669  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   670  		},
   671  		{
   672  			name:       "Authorization success: when the caller has owner access to the target of the FA with type application",
   673  			transactFn: txGen.ThatSucceeds,
   674  			faServiceFn: func() *automock.FormationAssignmentService {
   675  				faSvc := &automock.FormationAssignmentService{}
   676  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   677  				return faSvc
   678  			},
   679  			tenantRepoFn: func() *automock.TenantRepository {
   680  				tenantRepo := &automock.TenantRepository{}
   681  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   682  				return tenantRepo
   683  			},
   684  			appRepoFn: func() *automock.ApplicationRepository {
   685  				appRepo := &automock.ApplicationRepository{}
   686  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(intSysApp, nil)
   687  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(true, nil)
   688  				return appRepo
   689  			},
   690  			contextFn: func() context.Context {
   691  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   692  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   693  			},
   694  			hasURLVars:         true,
   695  			expectedStatusCode: http.StatusOK,
   696  			expectedErrOutput:  "",
   697  		},
   698  		{
   699  			name:       "Authorization fail: when the caller has owner access to the target of the FA with type application but the transaction fail",
   700  			transactFn: txGen.ThatFailsOnCommit,
   701  			faServiceFn: func() *automock.FormationAssignmentService {
   702  				faSvc := &automock.FormationAssignmentService{}
   703  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   704  				return faSvc
   705  			},
   706  			tenantRepoFn: func() *automock.TenantRepository {
   707  				tenantRepo := &automock.TenantRepository{}
   708  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   709  				return tenantRepo
   710  			},
   711  			appRepoFn: func() *automock.ApplicationRepository {
   712  				appRepo := &automock.ApplicationRepository{}
   713  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(intSysApp, nil)
   714  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(true, nil)
   715  				return appRepo
   716  			},
   717  			contextFn: func() context.Context {
   718  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   719  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   720  			},
   721  			hasURLVars:         true,
   722  			expectedStatusCode: http.StatusInternalServerError,
   723  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   724  		},
   725  		{
   726  			name:       "Authorization success: when the caller has owner access to the FA target's parent for type app that is made through subscription",
   727  			transactFn: txGen.ThatSucceeds,
   728  			faServiceFn: func() *automock.FormationAssignmentService {
   729  				faSvc := &automock.FormationAssignmentService{}
   730  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   731  				return faSvc
   732  			},
   733  			tenantRepoFn: func() *automock.TenantRepository {
   734  				tenantRepo := &automock.TenantRepository{}
   735  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   736  				return tenantRepo
   737  			},
   738  			appRepoFn: func() *automock.ApplicationRepository {
   739  				appRepo := &automock.ApplicationRepository{}
   740  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   741  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   742  				return appRepo
   743  			},
   744  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   745  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   746  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(true, nil)
   747  				return appTemplateRepo
   748  			},
   749  			labelRepoFn: func() *automock.LabelRepository {
   750  				lblRepo := &automock.LabelRepository{}
   751  				lblRepo.On("ListForGlobalObject", contextThatHasTenant(internalTntID), model.AppTemplateLabelableObject, appTemplateID).Return(appTemplateLbls, nil)
   752  				return lblRepo
   753  			},
   754  			consumerSubaccountLabelKey: consumerSubaccountLabelKey,
   755  			contextFn: func() context.Context {
   756  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   757  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   758  			},
   759  			hasURLVars:         true,
   760  			expectedStatusCode: http.StatusOK,
   761  			expectedErrOutput:  "",
   762  		},
   763  		{
   764  			name:       "Authz fail: when caller has owner access to FA target's parent for type app that is made through subscription but transact fail",
   765  			transactFn: txGen.ThatFailsOnCommit,
   766  			faServiceFn: func() *automock.FormationAssignmentService {
   767  				faSvc := &automock.FormationAssignmentService{}
   768  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceRuntimeAndTargetApp, nil)
   769  				return faSvc
   770  			},
   771  			tenantRepoFn: func() *automock.TenantRepository {
   772  				tenantRepo := &automock.TenantRepository{}
   773  				tenantRepo.On("Get", contextThatHasTenant(internalTntID), internalTntID).Return(fixBusinessTenantMapping(), nil)
   774  				return tenantRepo
   775  			},
   776  			appRepoFn: func() *automock.ApplicationRepository {
   777  				appRepo := &automock.ApplicationRepository{}
   778  				appRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(appWithAppTemplate, nil)
   779  				appRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   780  				return appRepo
   781  			},
   782  			appTemplateRepoFn: func() *automock.ApplicationTemplateRepository {
   783  				appTemplateRepo := &automock.ApplicationTemplateRepository{}
   784  				appTemplateRepo.On("Exists", contextThatHasTenant(internalTntID), appTemplateID).Return(true, nil)
   785  				return appTemplateRepo
   786  			},
   787  			labelRepoFn: func() *automock.LabelRepository {
   788  				lblRepo := &automock.LabelRepository{}
   789  				lblRepo.On("ListForGlobalObject", contextThatHasTenant(internalTntID), model.AppTemplateLabelableObject, appTemplateID).Return(appTemplateLbls, nil)
   790  				return lblRepo
   791  			},
   792  			consumerSubaccountLabelKey: consumerSubaccountLabelKey,
   793  			contextFn: func() context.Context {
   794  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   795  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   796  			},
   797  			hasURLVars:         true,
   798  			expectedStatusCode: http.StatusInternalServerError,
   799  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   800  		},
   801  		// Runtime authorization checks
   802  		{
   803  			name:       "Authorization fail: error when runtime owner existence check fail",
   804  			transactFn: txGen.ThatDoesntExpectCommit,
   805  			faServiceFn: func() *automock.FormationAssignmentService {
   806  				faSvc := &automock.FormationAssignmentService{}
   807  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil)
   808  				return faSvc
   809  			},
   810  			runtimeRepoFn: func() *automock.RuntimeRepository {
   811  				rtmRepo := &automock.RuntimeRepository{}
   812  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, testErr)
   813  				return rtmRepo
   814  			},
   815  			contextFn: func() context.Context {
   816  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   817  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   818  			},
   819  			hasURLVars:         true,
   820  			expectedStatusCode: http.StatusUnauthorized,
   821  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   822  		},
   823  		{
   824  			name:       "Authorization fail: error when the caller has NOT owner access to the formation assignment with target type runtime",
   825  			transactFn: txGen.ThatDoesntExpectCommit,
   826  			faServiceFn: func() *automock.FormationAssignmentService {
   827  				faSvc := &automock.FormationAssignmentService{}
   828  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil)
   829  				return faSvc
   830  			},
   831  			runtimeRepoFn: func() *automock.RuntimeRepository {
   832  				rtmRepo := &automock.RuntimeRepository{}
   833  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(false, nil)
   834  				return rtmRepo
   835  			},
   836  			contextFn: func() context.Context {
   837  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   838  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   839  			},
   840  			hasURLVars:         true,
   841  			expectedStatusCode: http.StatusUnauthorized,
   842  			expectedErrOutput:  "",
   843  		},
   844  		{
   845  			name:       "Authorization success: when the caller has owner access to the target of the formation assignment with type runtime",
   846  			transactFn: txGen.ThatSucceeds,
   847  			faServiceFn: func() *automock.FormationAssignmentService {
   848  				faSvc := &automock.FormationAssignmentService{}
   849  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil)
   850  				return faSvc
   851  			},
   852  			runtimeRepoFn: func() *automock.RuntimeRepository {
   853  				rtmRepo := &automock.RuntimeRepository{}
   854  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(true, nil)
   855  				return rtmRepo
   856  			},
   857  			contextFn: func() context.Context {
   858  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   859  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   860  			},
   861  			hasURLVars:         true,
   862  			expectedStatusCode: http.StatusOK,
   863  			expectedErrOutput:  "OK",
   864  		},
   865  		{
   866  			name:       "Authorization fail: when the caller has owner access to the target of the FA with type runtime but transaction fail",
   867  			transactFn: txGen.ThatFailsOnCommit,
   868  			faServiceFn: func() *automock.FormationAssignmentService {
   869  				faSvc := &automock.FormationAssignmentService{}
   870  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntime, nil)
   871  				return faSvc
   872  			},
   873  			runtimeRepoFn: func() *automock.RuntimeRepository {
   874  				rtmRepo := &automock.RuntimeRepository{}
   875  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(true, nil)
   876  				return rtmRepo
   877  			},
   878  			contextFn: func() context.Context {
   879  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   880  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   881  			},
   882  			hasURLVars:         true,
   883  			expectedStatusCode: http.StatusInternalServerError,
   884  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   885  		},
   886  		// Runtime context authorization checks
   887  		{
   888  			name:       "Authorization fail: error when getting runtime context globally",
   889  			transactFn: txGen.ThatDoesntExpectCommit,
   890  			faServiceFn: func() *automock.FormationAssignmentService {
   891  				faSvc := &automock.FormationAssignmentService{}
   892  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeContext, nil)
   893  				return faSvc
   894  			},
   895  			runtimeContextRepoFn: func() *automock.RuntimeContextRepository {
   896  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   897  				rtmCtxRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(nil, testErr)
   898  				return rtmCtxRepo
   899  			},
   900  			contextFn: func() context.Context {
   901  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   902  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   903  			},
   904  			hasURLVars:         true,
   905  			expectedStatusCode: http.StatusInternalServerError,
   906  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   907  		},
   908  		{
   909  			name:       "Authorization fail: error when runtime context owner check for runtime fails",
   910  			transactFn: txGen.ThatDoesntExpectCommit,
   911  			faServiceFn: func() *automock.FormationAssignmentService {
   912  				faSvc := &automock.FormationAssignmentService{}
   913  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeContext, nil).Once()
   914  				return faSvc
   915  			},
   916  			runtimeRepoFn: func() *automock.RuntimeRepository {
   917  				runtimeRepo := &automock.RuntimeRepository{}
   918  				runtimeRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, runtimeID).Return(false, testErr).Once()
   919  				return runtimeRepo
   920  			},
   921  			runtimeContextRepoFn: func() *automock.RuntimeContextRepository {
   922  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   923  				rtmCtxRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(rtmContext, nil).Once()
   924  				return rtmCtxRepo
   925  			},
   926  			contextFn: func() context.Context {
   927  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   928  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   929  			},
   930  			hasURLVars:         true,
   931  			expectedStatusCode: http.StatusUnauthorized,
   932  			expectedErrOutput:  "An unexpected error occurred while processing the request",
   933  		},
   934  		{
   935  			name:       "Authorization fail: when caller has NOT owner access to FA with target type rtm context made through subscription",
   936  			transactFn: txGen.ThatDoesntExpectCommit,
   937  			faServiceFn: func() *automock.FormationAssignmentService {
   938  				faSvc := &automock.FormationAssignmentService{}
   939  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeContext, nil)
   940  				return faSvc
   941  			},
   942  			runtimeRepoFn: func() *automock.RuntimeRepository {
   943  				rtmRepo := &automock.RuntimeRepository{}
   944  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, runtimeID).Return(false, nil)
   945  				return rtmRepo
   946  			},
   947  			runtimeContextRepoFn: func() *automock.RuntimeContextRepository {
   948  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   949  				rtmCtxRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(rtmContext, nil)
   950  				return rtmCtxRepo
   951  			},
   952  			contextFn: func() context.Context {
   953  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   954  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   955  			},
   956  			hasURLVars:         true,
   957  			expectedStatusCode: http.StatusUnauthorized,
   958  			expectedErrOutput:  "",
   959  		},
   960  		{
   961  			name:       "Authorization success: when caller has owner access to the target of the formation assignment with type rtm context",
   962  			transactFn: txGen.ThatSucceeds,
   963  			faServiceFn: func() *automock.FormationAssignmentService {
   964  				faSvc := &automock.FormationAssignmentService{}
   965  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeContext, nil)
   966  				return faSvc
   967  			},
   968  			runtimeRepoFn: func() *automock.RuntimeRepository {
   969  				rtmRepo := &automock.RuntimeRepository{}
   970  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, runtimeID).Return(true, nil)
   971  				return rtmRepo
   972  			},
   973  			runtimeContextRepoFn: func() *automock.RuntimeContextRepository {
   974  				rtmCtxRepo := &automock.RuntimeContextRepository{}
   975  				rtmCtxRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(rtmContext, nil)
   976  				return rtmCtxRepo
   977  			},
   978  			contextFn: func() context.Context {
   979  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
   980  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
   981  			},
   982  			hasURLVars:         true,
   983  			expectedStatusCode: http.StatusOK,
   984  			expectedErrOutput:  "",
   985  		},
   986  		{
   987  			name:       "Authorization fail: when caller has owner access to the target of the FA with type rtm context but transaction fail",
   988  			transactFn: txGen.ThatFailsOnCommit,
   989  			faServiceFn: func() *automock.FormationAssignmentService {
   990  				faSvc := &automock.FormationAssignmentService{}
   991  				faSvc.On("GetGlobalByIDAndFormationID", contextThatHasTenant(internalTntID), testFormationAssignmentID, testFormationID).Return(faWithSourceAppAndTargetRuntimeContext, nil)
   992  				return faSvc
   993  			},
   994  			runtimeRepoFn: func() *automock.RuntimeRepository {
   995  				rtmRepo := &automock.RuntimeRepository{}
   996  				rtmRepo.On("OwnerExists", contextThatHasTenant(internalTntID), internalTntID, runtimeID).Return(true, nil)
   997  				return rtmRepo
   998  			},
   999  			runtimeContextRepoFn: func() *automock.RuntimeContextRepository {
  1000  				rtmCtxRepo := &automock.RuntimeContextRepository{}
  1001  				rtmCtxRepo.On("GetByID", contextThatHasTenant(internalTntID), internalTntID, faTargetID).Return(rtmContext, nil)
  1002  				return rtmCtxRepo
  1003  			},
  1004  			contextFn: func() context.Context {
  1005  				c := fixGetConsumer(consumerUUID, consumer.ExternalCertificate)
  1006  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1007  			},
  1008  			hasURLVars:         true,
  1009  			expectedStatusCode: http.StatusInternalServerError,
  1010  			expectedErrOutput:  "An unexpected error occurred while processing the request",
  1011  		},
  1012  	}
  1013  
  1014  	for _, tCase := range testCases {
  1015  		t.Run(tCase.name, func(t *testing.T) {
  1016  			persist, transact := fixUnusedTransactioner()
  1017  			if tCase.transactFn != nil {
  1018  				persist, transact = tCase.transactFn()
  1019  			}
  1020  
  1021  			faSvc := fixUnusedFormationAssignmentSvc()
  1022  			if tCase.faServiceFn != nil {
  1023  				faSvc = tCase.faServiceFn()
  1024  			}
  1025  
  1026  			rtmRepo := fixUnusedRuntimeRepo()
  1027  			if tCase.runtimeRepoFn != nil {
  1028  				rtmRepo = tCase.runtimeRepoFn()
  1029  			}
  1030  
  1031  			rtmCtxRepo := fixUnusedRuntimeContextRepo()
  1032  			if tCase.runtimeContextRepoFn != nil {
  1033  				rtmCtxRepo = tCase.runtimeContextRepoFn()
  1034  			}
  1035  
  1036  			appRepo := fixUnusedAppRepo()
  1037  			if tCase.appRepoFn != nil {
  1038  				appRepo = tCase.appRepoFn()
  1039  			}
  1040  
  1041  			appTemplateRepo := fixUnusedAppTemplateRepo()
  1042  			if tCase.appTemplateRepoFn != nil {
  1043  				appTemplateRepo = tCase.appTemplateRepoFn()
  1044  			}
  1045  
  1046  			labelRepo := fixUnusedLabelRepo()
  1047  			if tCase.labelRepoFn != nil {
  1048  				labelRepo = tCase.labelRepoFn()
  1049  			}
  1050  
  1051  			tenantRepo := fixUnusedTenantRepo()
  1052  			if tCase.tenantRepoFn != nil {
  1053  				tenantRepo = tCase.tenantRepoFn()
  1054  			}
  1055  
  1056  			defer mock.AssertExpectationsForObjects(t, persist, transact, faSvc, rtmRepo, rtmCtxRepo, appRepo, appTemplateRepo, labelRepo)
  1057  
  1058  			// GIVEN
  1059  			fmAuthenticator := fm.NewFormationMappingAuthenticator(transact, faSvc, rtmRepo, rtmCtxRepo, appRepo, appTemplateRepo, labelRepo, nil, nil, tenantRepo, tCase.consumerSubaccountLabelKey)
  1060  			fmAuthMiddleware := fmAuthenticator.FormationAssignmentHandler()
  1061  			rw := httptest.NewRecorder()
  1062  
  1063  			httpMethod := http.MethodPatch
  1064  			if tCase.httpMethod != "" {
  1065  				httpMethod = tCase.httpMethod
  1066  			}
  1067  
  1068  			httpReq := fixRequestWithContext(t, tCase.contextFn(), httpMethod)
  1069  
  1070  			if tCase.hasURLVars {
  1071  				httpReq = mux.SetURLVars(httpReq, urlVars)
  1072  			}
  1073  
  1074  			// WHEN
  1075  			fmAuthMiddleware(fixTestHandler(t)).ServeHTTP(rw, httpReq)
  1076  
  1077  			// THEN
  1078  			require.Equal(t, tCase.expectedStatusCode, rw.Code)
  1079  			require.Contains(t, rw.Body.String(), tCase.expectedErrOutput)
  1080  		})
  1081  	}
  1082  }
  1083  
  1084  func TestAuthenticator_FormationHandler(t *testing.T) {
  1085  	urlVars := map[string]string{
  1086  		fm.FormationIDParam: testFormationID,
  1087  	}
  1088  
  1089  	consumerID := "2c755564-97ef-4499-8c88-7b8518edc171"
  1090  	leadingProductID := consumerID
  1091  	leadingProductID2 := "leading-product-id-2"
  1092  	leadingProductIDs := []string{leadingProductID, leadingProductID2}
  1093  
  1094  	formation := &model.Formation{
  1095  		ID:                  testFormationID,
  1096  		TenantID:            internalTntID,
  1097  		FormationTemplateID: testFormationTemplateID,
  1098  		Name:                testFormationName,
  1099  	}
  1100  
  1101  	formationTemplate := &model.FormationTemplate{
  1102  		ID:                testFormationTemplateID,
  1103  		Name:              "formationTemplateName",
  1104  		TenantID:          &internalTntID,
  1105  		LeadingProductIDs: leadingProductIDs,
  1106  	}
  1107  
  1108  	formationTemplateWithNonMatchingProductIDs := &model.FormationTemplate{
  1109  		ID:                testFormationTemplateID,
  1110  		Name:              "formationTemplateName",
  1111  		TenantID:          &internalTntID,
  1112  		LeadingProductIDs: []string{leadingProductID2},
  1113  	}
  1114  
  1115  	testCases := []struct {
  1116  		name                       string
  1117  		transactFn                 func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner)
  1118  		formationRepoFn            func() *automock.FormationRepository
  1119  		formationTemplateRepoFn    func() *automock.FormationTemplateRepository
  1120  		consumerSubaccountLabelKey string
  1121  		hasURLVars                 bool
  1122  		contextFn                  func() context.Context
  1123  		httpMethod                 string
  1124  		expectedStatusCode         int
  1125  		expectedErrOutput          string
  1126  	}{
  1127  		// Common authorization checks
  1128  		{
  1129  			name:       "Error when the http request method is not POST or DELETE",
  1130  			transactFn: fixUnusedTransactioner,
  1131  			contextFn: func() context.Context {
  1132  				return emptyCtx
  1133  			},
  1134  			hasURLVars:         true,
  1135  			httpMethod:         http.MethodGet,
  1136  			expectedStatusCode: http.StatusMethodNotAllowed,
  1137  			expectedErrOutput:  "",
  1138  		},
  1139  		{
  1140  			name: "Error when the required parameter is missing",
  1141  			contextFn: func() context.Context {
  1142  				return emptyCtx
  1143  			},
  1144  			expectedStatusCode: http.StatusBadRequest,
  1145  			expectedErrOutput:  fixBuildExpectedErrResponse(t, "Not all of the required parameters are provided"),
  1146  		},
  1147  		{
  1148  			name:       "Authorization success: when the consumer ID is one of the formation templates product IDs",
  1149  			transactFn: txGen.ThatSucceeds,
  1150  			formationRepoFn: func() *automock.FormationRepository {
  1151  				formationRepo := &automock.FormationRepository{}
  1152  				formationRepo.On("GetGlobalByID", contextThatHasTenant(internalTntID), testFormationID).Return(formation, nil).Once()
  1153  				return formationRepo
  1154  			},
  1155  			formationTemplateRepoFn: func() *automock.FormationTemplateRepository {
  1156  				ftRepo := &automock.FormationTemplateRepository{}
  1157  				ftRepo.On("Get", contextThatHasTenant(internalTntID), testFormationTemplateID).Return(formationTemplate, nil).Once()
  1158  				return ftRepo
  1159  			},
  1160  			contextFn: func() context.Context {
  1161  				c := fixGetConsumer(consumerID, consumer.ExternalCertificate)
  1162  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1163  			},
  1164  			hasURLVars:         true,
  1165  			expectedStatusCode: http.StatusOK,
  1166  		},
  1167  		{
  1168  			name:       "Unauthorized error when authorization check is unsuccessful but there is no error",
  1169  			transactFn: txGen.ThatSucceeds,
  1170  			formationRepoFn: func() *automock.FormationRepository {
  1171  				formationRepo := &automock.FormationRepository{}
  1172  				formationRepo.On("GetGlobalByID", contextThatHasTenant(internalTntID), testFormationID).Return(formation, nil).Once()
  1173  				return formationRepo
  1174  			},
  1175  			formationTemplateRepoFn: func() *automock.FormationTemplateRepository {
  1176  				ftRepo := &automock.FormationTemplateRepository{}
  1177  				ftRepo.On("Get", contextThatHasTenant(internalTntID), testFormationTemplateID).Return(formationTemplateWithNonMatchingProductIDs, nil).Once()
  1178  				return ftRepo
  1179  			},
  1180  			contextFn: func() context.Context {
  1181  				c := fixGetConsumer(consumerID, consumer.ExternalCertificate)
  1182  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1183  			},
  1184  			hasURLVars:         true,
  1185  			expectedStatusCode: http.StatusUnauthorized,
  1186  		},
  1187  		{
  1188  			name: "Authorization fail: error when consumer info is missing in the context",
  1189  			contextFn: func() context.Context {
  1190  				return emptyCtx
  1191  			},
  1192  			hasURLVars:         true,
  1193  			expectedStatusCode: http.StatusInternalServerError,
  1194  			expectedErrOutput:  "An unexpected error occurred while processing the request",
  1195  		},
  1196  		{
  1197  			name:       "Authorization fail: error when transaction begin fails",
  1198  			transactFn: txGen.ThatFailsOnBegin,
  1199  			contextFn: func() context.Context {
  1200  				c := fixGetConsumer(consumerID, consumer.ExternalCertificate)
  1201  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1202  			},
  1203  			hasURLVars:         true,
  1204  			expectedStatusCode: http.StatusInternalServerError,
  1205  			expectedErrOutput:  "An unexpected error occurred while processing the request",
  1206  		},
  1207  		{
  1208  			name:       "Authorization fail: error when getting formation fails",
  1209  			transactFn: txGen.ThatDoesntExpectCommit,
  1210  			formationRepoFn: func() *automock.FormationRepository {
  1211  				formationRepo := &automock.FormationRepository{}
  1212  				formationRepo.On("GetGlobalByID", contextThatHasTenant(internalTntID), testFormationID).Return(nil, testErr).Once()
  1213  				return formationRepo
  1214  			},
  1215  			contextFn: func() context.Context {
  1216  				c := fixGetConsumer(consumerID, consumer.ExternalCertificate)
  1217  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1218  			},
  1219  			hasURLVars:         true,
  1220  			expectedStatusCode: http.StatusInternalServerError,
  1221  			expectedErrOutput:  "An unexpected error occurred while processing the request",
  1222  		},
  1223  		{
  1224  			name:       "Authorization fail: error when getting formation template fails",
  1225  			transactFn: txGen.ThatDoesntExpectCommit,
  1226  			formationRepoFn: func() *automock.FormationRepository {
  1227  				formationRepo := &automock.FormationRepository{}
  1228  				formationRepo.On("GetGlobalByID", contextThatHasTenant(internalTntID), testFormationID).Return(formation, nil).Once()
  1229  				return formationRepo
  1230  			},
  1231  			formationTemplateRepoFn: func() *automock.FormationTemplateRepository {
  1232  				ftRepo := &automock.FormationTemplateRepository{}
  1233  				ftRepo.On("Get", contextThatHasTenant(internalTntID), testFormationTemplateID).Return(nil, testErr).Once()
  1234  				return ftRepo
  1235  			},
  1236  			contextFn: func() context.Context {
  1237  				c := fixGetConsumer(consumerID, consumer.ExternalCertificate)
  1238  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1239  			},
  1240  			hasURLVars:         true,
  1241  			expectedStatusCode: http.StatusInternalServerError,
  1242  			expectedErrOutput:  "An unexpected error occurred while processing the request",
  1243  		},
  1244  		{
  1245  			name:       "Authorization fail: error when committing transaction",
  1246  			transactFn: txGen.ThatFailsOnCommit,
  1247  			formationRepoFn: func() *automock.FormationRepository {
  1248  				formationRepo := &automock.FormationRepository{}
  1249  				formationRepo.On("GetGlobalByID", contextThatHasTenant(internalTntID), testFormationID).Return(formation, nil).Once()
  1250  				return formationRepo
  1251  			},
  1252  			formationTemplateRepoFn: func() *automock.FormationTemplateRepository {
  1253  				ftRepo := &automock.FormationTemplateRepository{}
  1254  				ftRepo.On("Get", contextThatHasTenant(internalTntID), testFormationTemplateID).Return(formationTemplateWithNonMatchingProductIDs, nil).Once()
  1255  				return ftRepo
  1256  			},
  1257  			contextFn: func() context.Context {
  1258  				c := fixGetConsumer(consumerID, consumer.ExternalCertificate)
  1259  				return fixContextWithTenantAndConsumer(c, internalTntID, externalTntID)
  1260  			},
  1261  			hasURLVars:         true,
  1262  			expectedStatusCode: http.StatusInternalServerError,
  1263  			expectedErrOutput:  "An unexpected error occurred while processing the request",
  1264  		},
  1265  	}
  1266  
  1267  	for _, tCase := range testCases {
  1268  		t.Run(tCase.name, func(t *testing.T) {
  1269  			persist, transact := fixUnusedTransactioner()
  1270  			if tCase.transactFn != nil {
  1271  				persist, transact = tCase.transactFn()
  1272  			}
  1273  
  1274  			formationRepo := fixUnusedFormationRepo()
  1275  			if tCase.formationRepoFn != nil {
  1276  				formationRepo = tCase.formationRepoFn()
  1277  			}
  1278  
  1279  			formationTemplateRepo := fixUnusedFormationTemplateRepo()
  1280  			if tCase.formationTemplateRepoFn != nil {
  1281  				formationTemplateRepo = tCase.formationTemplateRepoFn()
  1282  			}
  1283  
  1284  			defer mock.AssertExpectationsForObjects(t, persist, transact, formationRepo, formationTemplateRepo)
  1285  
  1286  			// GIVEN
  1287  			fmAuthenticator := fm.NewFormationMappingAuthenticator(transact, nil, nil, nil, nil, nil, nil, formationRepo, formationTemplateRepo, nil, tCase.consumerSubaccountLabelKey)
  1288  			formationAuthMiddleware := fmAuthenticator.FormationHandler()
  1289  			rw := httptest.NewRecorder()
  1290  
  1291  			httpMethod := http.MethodPatch
  1292  			if tCase.httpMethod != "" {
  1293  				httpMethod = tCase.httpMethod
  1294  			}
  1295  
  1296  			httpReq := fixRequestWithContext(t, tCase.contextFn(), httpMethod)
  1297  
  1298  			if tCase.hasURLVars {
  1299  				httpReq = mux.SetURLVars(httpReq, urlVars)
  1300  			}
  1301  
  1302  			// WHEN
  1303  			formationAuthMiddleware(fixTestHandler(t)).ServeHTTP(rw, httpReq)
  1304  
  1305  			// THEN
  1306  			require.Equal(t, tCase.expectedStatusCode, rw.Code)
  1307  			require.Contains(t, rw.Body.String(), tCase.expectedErrOutput)
  1308  		})
  1309  	}
  1310  }