github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/tenantfetchersvc/resync/event_page_test.go (about) 1 package resync_test 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "testing" 8 "text/template" 9 10 "github.com/kyma-incubator/compass/components/director/internal/tenantfetchersvc/resync" 11 "github.com/kyma-incubator/compass/components/director/pkg/tenant" 12 13 "github.com/kyma-incubator/compass/components/director/internal/model" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 func Test_getMovedSubaccounts(t *testing.T) { 18 ctx := context.TODO() 19 20 idField := "id" 21 entityTypeField := "type" 22 nameField := "name" 23 subdomainField := "subdomain" 24 regionField := "region" 25 parentID := "parent" 26 globalAccountKey := "gaID" 27 labelFieldMappingValue := "moved-label" 28 sourceTenantField := "source-tenant" 29 targetTenantField := "target-tenant" 30 expectedRuntime := model.MovedSubaccountMappingInput{ 31 SubaccountID: "label-value", 32 SourceTenant: "123", 33 TargetTenant: "456", 34 TenantMappingInput: model.BusinessTenantMappingInput{ 35 Name: "subaccount-name", 36 ExternalTenant: "label-value", 37 Parent: "parent", 38 Subdomain: "subdomain", 39 Region: "region", 40 Type: string(tenant.Subaccount), 41 Provider: "", 42 }, 43 } 44 fieldMapping := resync.TenantFieldMapping{ 45 IDField: idField, 46 NameField: nameField, 47 SubdomainField: subdomainField, 48 EntityTypeField: entityTypeField, 49 RegionField: regionField, 50 GlobalAccountKey: globalAccountKey, 51 EventsField: "events", 52 DetailsField: "details", 53 } 54 tests := []struct { 55 name string 56 detailsPairs [][]Pair 57 errorFunc func(*testing.T, error) 58 assertRuntimesFunc func(*testing.T, []model.MovedSubaccountMappingInput) 59 }{ 60 { 61 name: "successfully gets MovedSubaccountsMappingInputs for correct eventPage format", 62 detailsPairs: [][]Pair{ 63 { 64 {labelFieldMappingValue, "label-value"}, 65 {sourceTenantField, "123"}, 66 {targetTenantField, "456"}, 67 {nameField, "subaccount-name"}, 68 {subdomainField, "subdomain"}, 69 {regionField, "region"}, 70 }, 71 }, 72 assertRuntimesFunc: func(t *testing.T, runtimes []model.MovedSubaccountMappingInput) { 73 assert.Equal(t, 1, len(runtimes)) 74 assert.Equal(t, expectedRuntime, runtimes[0]) 75 }, 76 errorFunc: func(t *testing.T, err error) { 77 assert.NoError(t, err) 78 }, 79 }, 80 { 81 name: "empty mappings for get MovedSubaccountMappingInput when id field is invalid", 82 detailsPairs: [][]Pair{ 83 { 84 {"wrong", "label-value"}, 85 {sourceTenantField, "123"}, 86 {targetTenantField, "456"}, 87 }, 88 }, 89 errorFunc: func(t *testing.T, err error) { 90 assert.NoError(t, err) 91 }, 92 assertRuntimesFunc: func(t *testing.T, inputs []model.MovedSubaccountMappingInput) { 93 assert.Len(t, inputs, 0) 94 }, 95 }, 96 { 97 name: "empty mappings for get MovedSubaccountMappingInput when sourceTenant field is invalid", 98 detailsPairs: [][]Pair{ 99 { 100 {labelFieldMappingValue, "label-value"}, 101 {"wrong", "123"}, 102 {targetTenantField, "456"}, 103 }, 104 }, 105 errorFunc: func(t *testing.T, err error) { 106 assert.NoError(t, err) 107 }, 108 assertRuntimesFunc: func(t *testing.T, inputs []model.MovedSubaccountMappingInput) { 109 assert.Len(t, inputs, 0) 110 }, 111 }, 112 { 113 name: "empty mappings for get MovedSubaccountMappingInput when targetTenant field is invalid", 114 detailsPairs: [][]Pair{ 115 { 116 {labelFieldMappingValue, "label-value"}, 117 {sourceTenantField, "123"}, 118 {"wrong", "456"}, 119 }, 120 }, 121 errorFunc: func(t *testing.T, err error) { 122 assert.NoError(t, err) 123 }, 124 assertRuntimesFunc: func(t *testing.T, inputs []model.MovedSubaccountMappingInput) { 125 assert.Len(t, inputs, 0) 126 }, 127 }, 128 { 129 name: "events are skipped if some of the fields are invalid", 130 detailsPairs: [][]Pair{ 131 { 132 {labelFieldMappingValue, "label-value"}, 133 {sourceTenantField, "123"}, 134 {nameField, "name"}, 135 {regionField, "region"}, 136 {"wrong", "456"}, 137 }, 138 { 139 {labelFieldMappingValue, "label-value"}, 140 {sourceTenantField, "123"}, 141 {targetTenantField, "456"}, 142 {nameField, "name"}, 143 {regionField, "region"}, 144 }, 145 }, 146 errorFunc: func(t *testing.T, err error) { 147 assert.NoError(t, err) 148 }, 149 assertRuntimesFunc: func(t *testing.T, inputs []model.MovedSubaccountMappingInput) { 150 assert.Len(t, inputs, 1) 151 }, 152 }, 153 } 154 155 for _, test := range tests { 156 t.Run(test.name, func(t *testing.T) { 157 events := make([][]byte, 0, len(test.detailsPairs)) 158 for i, detailPair := range test.detailsPairs { 159 events = append(events, fixEventWithDetails(fmt.Sprintf("id%d", i), fmt.Sprintf("foo%d", i), "GlobalAccount", parentID, constructJSONObject(detailPair...), fieldMapping)) 160 } 161 page := resync.EventsPage{ 162 FieldMapping: fieldMapping, 163 MovedSubaccountsFieldMapping: resync.MovedSubaccountsFieldMapping{ 164 SubaccountID: labelFieldMappingValue, 165 SourceTenant: sourceTenantField, 166 TargetTenant: targetTenantField, 167 }, 168 Payload: []byte(fixTenantEventsResponseBytes(eventsToJSONArray(events...), len(test.detailsPairs), 1)), 169 } 170 171 runtimes := page.GetMovedSubaccounts(ctx) 172 test.assertRuntimesFunc(t, runtimes) 173 }) 174 } 175 } 176 177 func Test_getTenantMappings(t *testing.T) { 178 ctx := context.TODO() 179 180 idField := "id" 181 globalAccountGUIDField := "globalAccountGUID" 182 globalAccountKey := "gaID" 183 id := "1" 184 nameField := "name" 185 name := "test-name" 186 discriminatorField := "discriminator" 187 subdomainField := "subdomain" 188 subdomain := "test-subdomain" 189 providerName := "test-provider" 190 entityTypeField := "type" 191 entityType := "account" 192 193 expectedTenantMapping := model.BusinessTenantMappingInput{ 194 ExternalTenant: id, 195 Name: name, 196 Subdomain: subdomain, 197 Type: entityType, 198 Provider: providerName, 199 } 200 201 tests := []struct { 202 name string 203 detailsPairs [][]Pair 204 fieldMapping resync.TenantFieldMapping 205 errorFunc func(*testing.T, error) 206 assertTenantMappingFunc func(*testing.T, []model.BusinessTenantMappingInput) 207 }{ 208 { 209 name: "successfully gets businessTenantMappingInputs for correct eventPage format", 210 fieldMapping: resync.TenantFieldMapping{ 211 NameField: nameField, 212 IDField: idField, 213 SubdomainField: subdomainField, 214 EventsField: "events", 215 DetailsField: "details", 216 EntityTypeField: entityTypeField, 217 GlobalAccountGUIDField: globalAccountGUIDField, 218 GlobalAccountKey: globalAccountKey, 219 }, 220 errorFunc: func(t *testing.T, err error) { 221 assert.NoError(t, err) 222 }, 223 assertTenantMappingFunc: func(t *testing.T, tenantMappings []model.BusinessTenantMappingInput) { 224 assert.Equal(t, 1, len(tenantMappings)) 225 assert.Equal(t, expectedTenantMapping, tenantMappings[0]) 226 }, 227 detailsPairs: [][]Pair{ 228 { 229 {idField, id}, 230 {nameField, name}, 231 {subdomainField, subdomain}, 232 }, 233 }, 234 }, 235 { 236 name: "successfully gets businessTenantMappingInputs for correct eventPage format with discriminator field", 237 fieldMapping: resync.TenantFieldMapping{ 238 NameField: nameField, 239 IDField: idField, 240 EventsField: "events", 241 DetailsField: "details", 242 SubdomainField: "subdomain", 243 DiscriminatorField: discriminatorField, 244 DiscriminatorValue: "discriminator-value", 245 EntityTypeField: entityTypeField, 246 GlobalAccountGUIDField: globalAccountGUIDField, 247 GlobalAccountKey: globalAccountKey, 248 }, 249 errorFunc: func(t *testing.T, err error) { 250 assert.NoError(t, err) 251 }, 252 assertTenantMappingFunc: func(t *testing.T, tenantMappings []model.BusinessTenantMappingInput) { 253 assert.Equal(t, 1, len(tenantMappings)) 254 assert.Equal(t, expectedTenantMapping, tenantMappings[0]) 255 }, 256 detailsPairs: [][]Pair{ 257 { 258 {idField, id}, 259 {nameField, name}, 260 {discriminatorField, "discriminator-value"}, 261 {subdomainField, subdomain}, 262 {entityTypeField, tenant.TypeToStr(tenant.Account)}, 263 }, 264 }, 265 }, 266 { 267 name: "successfully gets businessTenantMappingInputs for eventPage with missing tenant names", 268 fieldMapping: resync.TenantFieldMapping{ 269 NameField: nameField, 270 IDField: idField, 271 EventsField: "events", 272 DetailsField: "details", 273 DiscriminatorField: discriminatorField, 274 DiscriminatorValue: "discriminator-value", 275 }, 276 errorFunc: func(t *testing.T, err error) { 277 assert.NoError(t, err) 278 }, 279 assertTenantMappingFunc: func(t *testing.T, tenantMappings []model.BusinessTenantMappingInput) { 280 assert.Len(t, tenantMappings, 1) 281 assert.Equal(t, expectedTenantMapping.ExternalTenant, tenantMappings[0].ExternalTenant) 282 assert.Empty(t, tenantMappings[0].Name) 283 }, 284 detailsPairs: [][]Pair{ 285 { 286 {idField, id}, 287 {"wrong", name}, 288 {discriminatorField, "discriminator-value"}, 289 }, 290 }, 291 }, 292 { 293 name: "empty mappings for get businessTenantMappingInputs when id field is wrong", 294 fieldMapping: resync.TenantFieldMapping{ 295 NameField: nameField, 296 IDField: idField, 297 EventsField: "events", 298 DetailsField: "details", 299 DiscriminatorField: discriminatorField, 300 DiscriminatorValue: "discriminator-value", 301 EntityTypeField: entityTypeField, 302 GlobalAccountKey: globalAccountKey, 303 }, 304 errorFunc: func(t *testing.T, err error) { 305 assert.NoError(t, err) 306 }, 307 assertTenantMappingFunc: func(t *testing.T, tenantMappings []model.BusinessTenantMappingInput) { 308 assert.Len(t, tenantMappings, 0) 309 }, 310 detailsPairs: [][]Pair{ 311 { 312 {"wrong", id}, 313 {nameField, name}, 314 {discriminatorField, "discriminator-value"}, 315 }, 316 }, 317 }, 318 { 319 name: "empty mappings for get businessTenantMappingInputs when discriminator field is wrong", 320 fieldMapping: resync.TenantFieldMapping{ 321 NameField: nameField, 322 IDField: idField, 323 EventsField: "events", 324 DetailsField: "details", 325 DiscriminatorField: discriminatorField, 326 DiscriminatorValue: "discriminator-value", 327 }, 328 errorFunc: func(t *testing.T, err error) { 329 assert.NoError(t, err) 330 }, 331 assertTenantMappingFunc: func(t *testing.T, tenantMappings []model.BusinessTenantMappingInput) { 332 assert.Len(t, tenantMappings, 0) 333 }, 334 detailsPairs: [][]Pair{ 335 { 336 {idField, id}, 337 {nameField, name}, 338 {"wrong", "discriminator-value"}, 339 }, 340 }, 341 }, 342 } 343 344 for _, test := range tests { 345 t.Run(test.name, func(t *testing.T) { 346 events := make([][]byte, 0, len(test.detailsPairs)) 347 for i, detailPair := range test.detailsPairs { 348 events = append(events, fixEventWithDetails(fmt.Sprintf("id%d", i), fmt.Sprintf("foo%d", i), "GlobalAccount", fmt.Sprintf("gaID%d", i), constructJSONObject(detailPair...), test.fieldMapping)) 349 } 350 page := resync.EventsPage{ 351 FieldMapping: test.fieldMapping, 352 ProviderName: providerName, 353 Payload: []byte(fixTenantEventsResponseBytes(eventsToJSONArray(events...), len(test.detailsPairs), 1)), 354 } 355 tenantMappings := page.GetTenantMappings(ctx, resync.CreatedAccountType) 356 test.assertTenantMappingFunc(t, tenantMappings) 357 }) 358 } 359 } 360 361 type Pair struct { 362 Key string 363 Value string 364 } 365 366 func constructJSONObject(pairs ...Pair) string { 367 var ( 368 templateName = "jsonObject" 369 jsonObjectTemplate = `{ 370 {{ $n := (len .) }} 371 {{range $i, $e := .}} 372 "{{$e.Key}}": "{{$e.Value}}"{{if ne (plus1 $i) $n }},{{end}} 373 {{end}} 374 }` 375 funcMap = template.FuncMap{ 376 "plus1": func(i int) int { 377 return i + 1 378 }, 379 } 380 t = template.Must(template.New(templateName).Funcs(funcMap).Parse(jsonObjectTemplate)) 381 buffer = bytes.NewBufferString("") 382 ) 383 384 template.Must(t, t.ExecuteTemplate(buffer, templateName, pairs)) 385 return buffer.String() 386 } 387 388 func fixEventWithDetails(id, name, entityType, globalAccountGUID, details string, fieldMapping resync.TenantFieldMapping) []byte { 389 return []byte(fmt.Sprintf(`{"%s":"%s", "%s":"%s", "%s":"%s","%s":"%s","%s":%s}`, fieldMapping.IDField, id, fieldMapping.NameField, name, fieldMapping.EntityTypeField, entityType, fieldMapping.GlobalAccountGUIDField, globalAccountGUID, fieldMapping.DetailsField, details)) 390 } 391 392 func fixTenantEventsResponseBytes(events []byte, total, pages int) resync.TenantEventsResponse { 393 return resync.TenantEventsResponse(fmt.Sprintf(`{ 394 "events": %s, 395 "total": %d, 396 "pages": %d, 397 }`, string(events), total, pages)) 398 } 399 400 func eventsToJSONArrayBytes(events ...[]byte) []byte { 401 return []byte(fmt.Sprintf(`[%s]`, bytes.Join(events, []byte(",")))) 402 }