github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/tenantfetchersvc/resync/tenant_mover_test.go (about) 1 package resync_test 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 8 domaintenant "github.com/kyma-incubator/compass/components/director/internal/domain/tenant" 9 "github.com/kyma-incubator/compass/components/director/internal/labelfilter" 10 "github.com/kyma-incubator/compass/components/director/internal/model" 11 "github.com/kyma-incubator/compass/components/director/internal/tenantfetchersvc/resync" 12 "github.com/kyma-incubator/compass/components/director/internal/tenantfetchersvc/resync/automock" 13 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 14 persistenceautomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock" 15 "github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest" 16 "github.com/kyma-incubator/compass/components/director/pkg/str" 17 "github.com/kyma-incubator/compass/components/director/pkg/tenant" 18 "github.com/stretchr/testify/mock" 19 "github.com/stretchr/testify/require" 20 ) 21 22 func TestTenantMover_TenantsToMove(t *testing.T) { 23 const ( 24 timestamp = "1234567899987" 25 26 sourceParentTenantID = "d65e725e-f9a2-4a2a-b349-6487ab084ebc" 27 targetParentTenantID = "7fb04de7-b397-4b86-98f5-f3af8ac1da0c" 28 ) 29 30 ctx := context.TODO() 31 testLicenseType := "LICENSETYPE" 32 tenantConverter := domaintenant.NewConverter() 33 jobConfig := configForTenantType(tenant.Subaccount) 34 jobConfig.EventsConfig.QueryConfig.RegionField = "region" 35 36 movedSubaccount1 := model.MovedSubaccountMappingInput{ 37 TenantMappingInput: fixBusinessTenantMappingInput("1", provider, "subdomain-1", "", sourceParentTenantID, tenant.Subaccount, &testLicenseType), 38 SubaccountID: "1", 39 SourceTenant: sourceParentTenantID, 40 TargetTenant: targetParentTenantID, 41 } 42 movedSubaccount2 := model.MovedSubaccountMappingInput{ 43 TenantMappingInput: fixBusinessTenantMappingInput("2", provider, "subdomain-2", "", sourceParentTenantID, tenant.Subaccount, nil), 44 SubaccountID: "2", 45 SourceTenant: sourceParentTenantID, 46 TargetTenant: targetParentTenantID, 47 } 48 49 event1 := fixEvent(t, "Subaccount", movedSubaccount1.TenantMappingInput.Parent, movedEventFieldsFromTenant(jobConfig.APIConfig.TenantFieldMapping, jobConfig.APIConfig.MovedSubaccountsFieldMapping, movedSubaccount1)) 50 event2 := fixEvent(t, "Subaccount", movedSubaccount2.TenantMappingInput.Parent, movedEventFieldsFromTenant(jobConfig.APIConfig.TenantFieldMapping, jobConfig.APIConfig.MovedSubaccountsFieldMapping, movedSubaccount2)) 51 52 pageOneQueryParams := resync.QueryParams{ 53 jobConfig.PageSizeField: "1", 54 jobConfig.PageNumField: "1", 55 jobConfig.TimestampField: timestamp, 56 jobConfig.EventsConfig.QueryConfig.RegionField: region, 57 } 58 59 testCases := []struct { 60 name string 61 directorClientFn func() *automock.DirectorGraphQLClient 62 apiClientFn func(resync.JobConfig) *automock.EventAPIClient 63 runtimeSvcFn func() *automock.RuntimeService 64 labelRepoFn func() *automock.LabelRepo 65 tenantStorageSvcFn func() *automock.TenantStorageService 66 expectedTenants []model.MovedSubaccountMappingInput 67 expectedErrMsg string 68 }{ 69 { 70 name: "Success when only one page is returned for moved tenants events", 71 directorClientFn: func() *automock.DirectorGraphQLClient { return &automock.DirectorGraphQLClient{} }, 72 apiClientFn: func(cfg resync.JobConfig) *automock.EventAPIClient { 73 client := &automock.EventAPIClient{} 74 client.On("FetchTenantEventsPage", ctx, resync.MovedSubaccountType, pageOneQueryParams).Return(fixTenantEventsResponse(eventsToJSONArray(event1), 1, 1, cfg.APIConfig.TenantFieldMapping, cfg.APIConfig.MovedSubaccountsFieldMapping, cfg.TenantProvider), nil).Once() 75 return client 76 }, 77 expectedTenants: []model.MovedSubaccountMappingInput{movedSubaccount1}, 78 }, 79 { 80 name: "Success when two pages are returned for moved tenants events", 81 directorClientFn: func() *automock.DirectorGraphQLClient { return &automock.DirectorGraphQLClient{} }, 82 apiClientFn: func(cfg resync.JobConfig) *automock.EventAPIClient { 83 pageTwoQueryParams := resync.QueryParams{ 84 "pageSize": "1", 85 "pageNum": "2", 86 "region": region, 87 "timestamp": timestamp, 88 } 89 90 client := &automock.EventAPIClient{} 91 client.On("FetchTenantEventsPage", ctx, resync.MovedSubaccountType, pageOneQueryParams).Return(fixTenantEventsResponse(eventsToJSONArray(event1), 2, 2, cfg.APIConfig.TenantFieldMapping, cfg.APIConfig.MovedSubaccountsFieldMapping, cfg.TenantProvider), nil).Once() 92 client.On("FetchTenantEventsPage", ctx, resync.MovedSubaccountType, pageTwoQueryParams).Return(fixTenantEventsResponse(eventsToJSONArray(event2), 2, 2, cfg.APIConfig.TenantFieldMapping, cfg.APIConfig.MovedSubaccountsFieldMapping, cfg.TenantProvider), nil).Once() 93 94 return client 95 }, 96 expectedTenants: []model.MovedSubaccountMappingInput{movedSubaccount1, movedSubaccount2}, 97 }, 98 { 99 name: "Fail when fetching moved tenants events returns an error", 100 directorClientFn: func() *automock.DirectorGraphQLClient { return &automock.DirectorGraphQLClient{} }, 101 apiClientFn: func(cfg resync.JobConfig) *automock.EventAPIClient { 102 client := &automock.EventAPIClient{} 103 client.On("FetchTenantEventsPage", ctx, resync.MovedSubaccountType, pageOneQueryParams).Return(nil, errors.New("failed to get moved")).Once() 104 return client 105 }, 106 expectedErrMsg: "while fetching moved tenants", 107 }, 108 } 109 110 for _, tc := range testCases { 111 t.Run(tc.name, func(t *testing.T) { 112 directorClient := tc.directorClientFn() 113 eventAPIClient := tc.apiClientFn(jobConfig) 114 storageSvc := &automock.TenantStorageService{} 115 runtimeSvc := &automock.RuntimeService{} 116 labelRepo := &automock.LabelRepo{} 117 txGen := txtest.NewTransactionContextGenerator(nil) 118 persist, transact := txGen.ThatDoesntStartTransaction() 119 defer mock.AssertExpectationsForObjects(t, directorClient, eventAPIClient, storageSvc, runtimeSvc, labelRepo, persist, transact) 120 121 mover := resync.NewSubaccountsMover(jobConfig, transact, directorClient, eventAPIClient, tenantConverter, storageSvc, runtimeSvc, labelRepo) 122 res, err := mover.TenantsToMove(ctx, region, timestamp) 123 if len(tc.expectedErrMsg) > 0 { 124 require.Error(t, err) 125 require.Contains(t, err.Error(), tc.expectedErrMsg) 126 } else { 127 require.NoError(t, err) 128 require.EqualValues(t, tc.expectedTenants, res) 129 } 130 }) 131 } 132 } 133 134 func TestTenantMover_MoveTenants(t *testing.T) { 135 const ( 136 provider = "external-service" 137 138 subaccountExternalTenant = "3daf8389-7f3e-41f7-94d9-75576ac80bee" 139 subaccountInternalTenant = "f384fa42-41f2-4490-b9b7-95d8ee03f785" 140 141 sourceParentTenantID = "d65e725e-f9a2-4a2a-b349-6487ab084ebc" 142 targetParentTenantID = "7fb04de7-b397-4b86-98f5-f3af8ac1da0c" 143 ) 144 145 ctx := context.TODO() 146 txGen := txtest.NewTransactionContextGenerator(errors.New("test err")) 147 148 // GIVEN 149 tenantConverter := domaintenant.NewConverter() 150 151 var subaccountFromDB *model.BusinessTenantMapping 152 init := func() { 153 subaccountFromDB = &model.BusinessTenantMapping{ 154 ID: subaccountInternalTenant, 155 Name: subaccountExternalTenant, 156 ExternalTenant: subaccountExternalTenant, 157 Parent: sourceParentTenantID, 158 Type: tenant.Subaccount, 159 Provider: provider, 160 } 161 } 162 163 targetParent := &model.BusinessTenantMapping{ 164 ID: "05a2a8ed-66b9-4978-86b9-5167fb43520f", 165 ExternalTenant: targetParentTenantID, 166 } 167 sourceParent := &model.BusinessTenantMapping{ 168 ID: "83711a81-4b07-4b21-b1b2-042135800039", 169 ExternalTenant: sourceParentTenantID, 170 } 171 172 movedSubaccountInput := graphql.BusinessTenantMappingInput{ 173 Name: subaccountExternalTenant, 174 ExternalTenant: subaccountExternalTenant, 175 Parent: str.Ptr(targetParent.ID), 176 Subdomain: str.Ptr(""), 177 Region: str.Ptr(""), 178 Type: string(tenant.Subaccount), 179 Provider: provider, 180 } 181 182 movedSubaccount1 := model.MovedSubaccountMappingInput{ 183 TenantMappingInput: fixBusinessTenantMappingInput(subaccountExternalTenant, provider, "", "", sourceParentTenantID, tenant.Subaccount, nil), 184 SubaccountID: subaccountExternalTenant, 185 SourceTenant: sourceParentTenantID, 186 TargetTenant: targetParentTenantID, 187 } 188 189 ctxWithSubaccountMatcher := mock.MatchedBy(func(ctx context.Context) bool { 190 tenantID, err := domaintenant.LoadFromContext(ctx) 191 require.NoError(t, err) 192 eq := tenantID == subaccountInternalTenant 193 return eq 194 }) 195 196 subaccountRuntime := &model.Runtime{ 197 ID: "35ab420d-1c67-4d06-9567-dbba8f95ea95", 198 } 199 200 testCases := []struct { 201 name string 202 jobConfigFn func() resync.JobConfig 203 transactionerFn func() (*persistenceautomock.PersistenceTx, *persistenceautomock.Transactioner) 204 directorClientFn func() *automock.DirectorGraphQLClient 205 runtimeSvcFn func() *automock.RuntimeService 206 labelRepoFn func() *automock.LabelRepo 207 tenantStorageSvcFn func([]model.MovedSubaccountMappingInput) *automock.TenantStorageService 208 tenantsInput []model.MovedSubaccountMappingInput 209 expectedErrMsg string 210 }{ 211 { 212 name: "Success when subaccount is moved to an existing parent tenant", 213 jobConfigFn: func() resync.JobConfig { 214 return configForTenantType(tenant.Subaccount) 215 }, 216 transactionerFn: txGen.ThatSucceeds, 217 directorClientFn: func() *automock.DirectorGraphQLClient { 218 client := &automock.DirectorGraphQLClient{} 219 client.On("UpdateTenant", txtest.CtxWithDBMatcher(), subaccountInternalTenant, movedSubaccountInput).Return(nil) 220 return client 221 }, 222 runtimeSvcFn: func() *automock.RuntimeService { 223 svc := &automock.RuntimeService{} 224 var emptyFilters []*labelfilter.LabelFilter 225 226 svc.On("ListByFilters", ctxWithSubaccountMatcher, emptyFilters).Return(nil, nil).Once() 227 return svc 228 }, 229 labelRepoFn: func() *automock.LabelRepo { return &automock.LabelRepo{} }, 230 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 231 svc := &automock.TenantStorageService{} 232 tnt := input[0] 233 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{targetParent}, nil).Once() 234 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.SubaccountID}).Return([]*model.BusinessTenantMapping{subaccountFromDB}, nil).Once() 235 return svc 236 }, 237 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 238 }, 239 { 240 name: "Success when subaccount is created in the correct parent tenant", 241 jobConfigFn: func() resync.JobConfig { 242 return configForTenantType(tenant.Subaccount) 243 }, 244 transactionerFn: txGen.ThatSucceeds, 245 directorClientFn: func() *automock.DirectorGraphQLClient { 246 client := &automock.DirectorGraphQLClient{} 247 248 client.On("WriteTenants", txtest.CtxWithDBMatcher(), []graphql.BusinessTenantMappingInput{movedSubaccountInput}).Return(nil).Once() 249 return client 250 }, 251 runtimeSvcFn: func() *automock.RuntimeService { return &automock.RuntimeService{} }, 252 labelRepoFn: func() *automock.LabelRepo { return &automock.LabelRepo{} }, 253 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 254 svc := &automock.TenantStorageService{} 255 tnt := input[0] 256 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{targetParent}, nil).Once() 257 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.SubaccountID}).Return([]*model.BusinessTenantMapping{}, nil).Once() 258 return svc 259 }, 260 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 261 }, 262 { 263 name: "Success when subaccount is not in a formation", 264 jobConfigFn: func() resync.JobConfig { 265 return configForTenantType(tenant.Subaccount) 266 }, 267 transactionerFn: txGen.ThatSucceeds, 268 directorClientFn: func() *automock.DirectorGraphQLClient { 269 client := &automock.DirectorGraphQLClient{} 270 client.On("UpdateTenant", txtest.CtxWithDBMatcher(), subaccountInternalTenant, movedSubaccountInput).Return(nil) 271 return client 272 }, 273 runtimeSvcFn: func() *automock.RuntimeService { 274 svc := &automock.RuntimeService{} 275 var emptyFilters []*labelfilter.LabelFilter 276 277 svc.On("ListByFilters", ctxWithSubaccountMatcher, emptyFilters).Return([]*model.Runtime{subaccountRuntime}, nil).Once() 278 return svc 279 }, 280 labelRepoFn: func() *automock.LabelRepo { 281 repo := &automock.LabelRepo{} 282 repo.On("GetScenarioLabelsForRuntimes", txtest.CtxWithDBMatcher(), sourceParent.ID, []string{subaccountRuntime.ID}).Return(nil, nil).Once() 283 return repo 284 }, 285 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 286 svc := &automock.TenantStorageService{} 287 tnt := input[0] 288 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{targetParent}, nil).Once() 289 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.SubaccountID}).Return([]*model.BusinessTenantMapping{subaccountFromDB}, nil).Once() 290 svc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), sourceParentTenantID).Return(sourceParent, nil).Once() 291 return svc 292 }, 293 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 294 }, 295 { 296 name: "Success when subaccount is in the default formation", 297 jobConfigFn: func() resync.JobConfig { 298 return configForTenantType(tenant.Subaccount) 299 }, 300 transactionerFn: txGen.ThatSucceeds, 301 directorClientFn: func() *automock.DirectorGraphQLClient { 302 client := &automock.DirectorGraphQLClient{} 303 client.On("UpdateTenant", txtest.CtxWithDBMatcher(), subaccountInternalTenant, movedSubaccountInput).Return(nil) 304 return client 305 }, 306 runtimeSvcFn: func() *automock.RuntimeService { 307 svc := &automock.RuntimeService{} 308 var emptyFilters []*labelfilter.LabelFilter 309 310 svc.On("ListByFilters", ctxWithSubaccountMatcher, emptyFilters).Return([]*model.Runtime{subaccountRuntime}, nil).Once() 311 return svc 312 }, 313 labelRepoFn: func() *automock.LabelRepo { 314 repo := &automock.LabelRepo{} 315 defaultLabel := []model.Label{{Value: []interface{}{"DEFAULT"}}} 316 repo.On("GetScenarioLabelsForRuntimes", txtest.CtxWithDBMatcher(), sourceParent.ID, []string{subaccountRuntime.ID}).Return(defaultLabel, nil).Once() 317 return repo 318 }, 319 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 320 svc := &automock.TenantStorageService{} 321 tnt := input[0] 322 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{targetParent}, nil).Once() 323 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.SubaccountID}).Return([]*model.BusinessTenantMapping{subaccountFromDB}, nil).Once() 324 svc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), sourceParentTenantID).Return(sourceParent, nil).Once() 325 return svc 326 }, 327 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 328 }, 329 { 330 name: "Success when target parent tenant does not exist: tenant is skipped", 331 jobConfigFn: func() resync.JobConfig { 332 return configForTenantType(tenant.Subaccount) 333 }, 334 transactionerFn: txGen.ThatSucceeds, 335 directorClientFn: func() *automock.DirectorGraphQLClient { return &automock.DirectorGraphQLClient{} }, 336 runtimeSvcFn: func() *automock.RuntimeService { return &automock.RuntimeService{} }, 337 labelRepoFn: func() *automock.LabelRepo { return &automock.LabelRepo{} }, 338 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 339 svc := &automock.TenantStorageService{} 340 tnt := input[0] 341 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{}, nil).Once() 342 return svc 343 }, 344 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 345 }, 346 { 347 name: "Success when subaccount is already moved", 348 jobConfigFn: func() resync.JobConfig { 349 return configForTenantType(tenant.Subaccount) 350 }, 351 transactionerFn: txGen.ThatSucceeds, 352 directorClientFn: func() *automock.DirectorGraphQLClient { return &automock.DirectorGraphQLClient{} }, 353 runtimeSvcFn: func() *automock.RuntimeService { return &automock.RuntimeService{} }, 354 labelRepoFn: func() *automock.LabelRepo { return &automock.LabelRepo{} }, 355 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 356 svc := &automock.TenantStorageService{} 357 tnt := input[0] 358 subaccountFromDBWithNewParent := *subaccountFromDB 359 subaccountFromDBWithNewParent.Parent = targetParent.ID 360 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{targetParent}, nil).Once() 361 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.SubaccountID}).Return([]*model.BusinessTenantMapping{&subaccountFromDBWithNewParent}, nil).Once() 362 return svc 363 }, 364 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 365 }, 366 { 367 name: "Fail when subaccount is in formation", 368 jobConfigFn: func() resync.JobConfig { 369 return configForTenantType(tenant.Subaccount) 370 }, 371 transactionerFn: txGen.ThatDoesntExpectCommit, 372 directorClientFn: func() *automock.DirectorGraphQLClient { 373 client := &automock.DirectorGraphQLClient{} 374 //client.On("UpdateTenant", txtest.CtxWithDBMatcher(), subaccountInternalTenant, movedSubaccountInput).Return(nil) 375 return client 376 }, 377 runtimeSvcFn: func() *automock.RuntimeService { 378 svc := &automock.RuntimeService{} 379 var emptyFilters []*labelfilter.LabelFilter 380 381 svc.On("ListByFilters", ctxWithSubaccountMatcher, emptyFilters).Return([]*model.Runtime{subaccountRuntime}, nil).Once() 382 return svc 383 }, 384 labelRepoFn: func() *automock.LabelRepo { 385 repo := &automock.LabelRepo{} 386 label := []model.Label{{Value: []interface{}{"my-scenario"}}} 387 repo.On("GetScenarioLabelsForRuntimes", txtest.CtxWithDBMatcher(), sourceParent.ID, []string{subaccountRuntime.ID}).Return(label, nil).Once() 388 return repo 389 }, 390 tenantStorageSvcFn: func(input []model.MovedSubaccountMappingInput) *automock.TenantStorageService { 391 svc := &automock.TenantStorageService{} 392 tnt := input[0] 393 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.TargetTenant}).Return([]*model.BusinessTenantMapping{targetParent}, nil).Once() 394 svc.On("ListsByExternalIDs", txtest.CtxWithDBMatcher(), []string{tnt.SubaccountID}).Return([]*model.BusinessTenantMapping{subaccountFromDB}, nil).Once() 395 svc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), sourceParentTenantID).Return(sourceParent, nil).Once() 396 return svc 397 }, 398 tenantsInput: []model.MovedSubaccountMappingInput{movedSubaccount1}, 399 expectedErrMsg: "is in scenario", 400 }, 401 } 402 403 for _, tc := range testCases { 404 t.Run(tc.name, func(t *testing.T) { 405 cfg := tc.jobConfigFn() 406 init() 407 eventAPIClient := &automock.EventAPIClient{} 408 persist, transact := tc.transactionerFn() 409 directorClient := tc.directorClientFn() 410 storageSvc := tc.tenantStorageSvcFn(tc.tenantsInput) 411 runtimeSvc := tc.runtimeSvcFn() 412 labelRepo := tc.labelRepoFn() 413 defer mock.AssertExpectationsForObjects(t, persist, transact, directorClient, eventAPIClient, storageSvc, runtimeSvc, labelRepo) 414 415 mover := resync.NewSubaccountsMover(cfg, transact, directorClient, eventAPIClient, tenantConverter, storageSvc, runtimeSvc, labelRepo) 416 err := mover.MoveTenants(ctx, tc.tenantsInput) 417 if len(tc.expectedErrMsg) > 0 { 418 require.Error(t, err) 419 require.Contains(t, err.Error(), tc.expectedErrMsg) 420 } else { 421 require.NoError(t, err) 422 } 423 }) 424 } 425 } 426 427 func movedEventFieldsFromTenant(tenantFieldMapping resync.TenantFieldMapping, movedSAFieldMapping resync.MovedSubaccountsFieldMapping, tenantInput model.MovedSubaccountMappingInput) map[string]string { 428 eventFields := eventFieldsFromTenant(tenant.Subaccount, tenantFieldMapping, tenantInput.TenantMappingInput) 429 eventFields[movedSAFieldMapping.SourceTenant] = tenantInput.SourceTenant 430 eventFields[movedSAFieldMapping.TargetTenant] = tenantInput.TargetTenant 431 eventFields[movedSAFieldMapping.SubaccountID] = tenantInput.SubaccountID 432 return eventFields 433 }