github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/tenant/repository_test.go (about) 1 package tenant_test 2 3 import ( 4 "context" 5 "database/sql" 6 "database/sql/driver" 7 "fmt" 8 "regexp" 9 "strings" 10 "testing" 11 12 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 13 "github.com/kyma-incubator/compass/components/director/pkg/str" 14 15 "github.com/google/uuid" 16 "github.com/jmoiron/sqlx" 17 18 "github.com/kyma-incubator/compass/components/director/pkg/pagination" 19 20 "github.com/kyma-incubator/compass/components/director/internal/repo" 21 22 "github.com/kyma-incubator/compass/components/director/pkg/resource" 23 24 "github.com/kyma-incubator/compass/components/director/internal/domain/tenant" 25 tenantEntity "github.com/kyma-incubator/compass/components/director/pkg/tenant" 26 27 "github.com/DATA-DOG/go-sqlmock" 28 "github.com/kyma-incubator/compass/components/director/internal/domain/tenant/automock" 29 "github.com/kyma-incubator/compass/components/director/internal/model" 30 "github.com/kyma-incubator/compass/components/director/internal/repo/testdb" 31 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 32 "github.com/stretchr/testify/assert" 33 "github.com/stretchr/testify/require" 34 ) 35 36 func TestPgRepository_Upsert(t *testing.T) { 37 t.Run("Success", func(t *testing.T) { 38 // GIVEN 39 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 40 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 41 42 mockConverter := &automock.Converter{} 43 defer mockConverter.AssertExpectations(t) 44 mockConverter.On("ToEntity", tenantMappingModel).Return(tenantMappingEntity).Once() 45 db, dbMock := testdb.MockDatabase(t) 46 defer dbMock.AssertExpectations(t) 47 dbMock.ExpectExec(regexp.QuoteMeta(`INSERT INTO public.business_tenant_mappings ( id, external_name, external_tenant, parent, type, provider_name, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT ( external_tenant ) DO UPDATE SET external_name=EXCLUDED.external_name`)). 48 WithArgs(fixTenantMappingCreateArgs(*tenantMappingEntity)...). 49 WillReturnResult(sqlmock.NewResult(1, 1)) 50 51 ctx := persistence.SaveToContext(context.TODO(), db) 52 tenantMappingrepo := tenant.NewRepository(mockConverter) 53 54 // WHEN 55 err := tenantMappingrepo.Upsert(ctx, *tenantMappingModel) 56 57 // THEN 58 require.NoError(t, err) 59 }) 60 61 t.Run("Error when upserting", func(t *testing.T) { 62 // GIVEN 63 tenantModel := newModelBusinessTenantMapping(testID, testName) 64 tenantEntity := newEntityBusinessTenantMapping(testID, testName) 65 66 mockConverter := &automock.Converter{} 67 defer mockConverter.AssertExpectations(t) 68 mockConverter.On("ToEntity", tenantModel).Return(tenantEntity).Once() 69 db, dbMock := testdb.MockDatabase(t) 70 defer dbMock.AssertExpectations(t) 71 dbMock.ExpectExec(regexp.QuoteMeta(`INSERT INTO public.business_tenant_mappings ( id, external_name, external_tenant, parent, type, provider_name, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT ( external_tenant ) DO UPDATE SET external_name=EXCLUDED.external_name`)). 72 WithArgs(fixTenantMappingCreateArgs(*tenantEntity)...). 73 WillReturnError(testError) 74 75 ctx := persistence.SaveToContext(context.TODO(), db) 76 tenantMappingRepo := tenant.NewRepository(mockConverter) 77 78 // WHEN 79 err := tenantMappingRepo.Upsert(ctx, *tenantModel) 80 81 // THEN 82 require.Error(t, err) 83 assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 84 }) 85 } 86 87 func TestPgRepository_UnsafeCreate(t *testing.T) { 88 t.Run("Success", func(t *testing.T) { 89 // GIVEN 90 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 91 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 92 93 mockConverter := &automock.Converter{} 94 defer mockConverter.AssertExpectations(t) 95 mockConverter.On("ToEntity", tenantMappingModel).Return(tenantMappingEntity).Once() 96 db, dbMock := testdb.MockDatabase(t) 97 defer dbMock.AssertExpectations(t) 98 dbMock.ExpectExec(regexp.QuoteMeta(`INSERT INTO public.business_tenant_mappings ( id, external_name, external_tenant, parent, type, provider_name, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT ( external_tenant ) DO NOTHING`)). 99 WithArgs(fixTenantMappingCreateArgs(*tenantMappingEntity)...). 100 WillReturnResult(sqlmock.NewResult(-1, 1)) 101 102 ctx := persistence.SaveToContext(context.TODO(), db) 103 tenantMappingrepo := tenant.NewRepository(mockConverter) 104 105 // WHEN 106 err := tenantMappingrepo.UnsafeCreate(ctx, *tenantMappingModel) 107 108 // THEN 109 require.NoError(t, err) 110 }) 111 112 t.Run("Error when creating", func(t *testing.T) { 113 // GIVEN 114 tenantModel := newModelBusinessTenantMapping(testID, testName) 115 tenantEntity := newEntityBusinessTenantMapping(testID, testName) 116 117 mockConverter := &automock.Converter{} 118 defer mockConverter.AssertExpectations(t) 119 mockConverter.On("ToEntity", tenantModel).Return(tenantEntity).Once() 120 db, dbMock := testdb.MockDatabase(t) 121 defer dbMock.AssertExpectations(t) 122 dbMock.ExpectExec(regexp.QuoteMeta(`INSERT INTO public.business_tenant_mappings ( id, external_name, external_tenant, parent, type, provider_name, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) ON CONFLICT ( external_tenant ) DO NOTHING`)). 123 WithArgs(fixTenantMappingCreateArgs(*tenantEntity)...). 124 WillReturnError(testError) 125 126 ctx := persistence.SaveToContext(context.TODO(), db) 127 tenantMappingRepo := tenant.NewRepository(mockConverter) 128 129 // WHEN 130 err := tenantMappingRepo.UnsafeCreate(ctx, *tenantModel) 131 132 // THEN 133 require.Error(t, err) 134 assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 135 }) 136 } 137 138 func TestPgRepository_Get(t *testing.T) { 139 t.Run("Success", func(t *testing.T) { 140 // GIVEN 141 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 142 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 143 144 mockConverter := &automock.Converter{} 145 defer mockConverter.AssertExpectations(t) 146 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 147 db, dbMock := testdb.MockDatabase(t) 148 defer dbMock.AssertExpectations(t) 149 rowsToReturn := fixSQLRows([]sqlRow{ 150 {id: testID, name: testName, externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 151 }) 152 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 153 WithArgs(testID, tenantEntity.Inactive). 154 WillReturnRows(rowsToReturn) 155 156 ctx := persistence.SaveToContext(context.TODO(), db) 157 tenantMappingRepo := tenant.NewRepository(mockConverter) 158 159 // WHEN 160 result, err := tenantMappingRepo.Get(ctx, testID) 161 162 // THEN 163 require.NoError(t, err) 164 require.NotNil(t, result) 165 assert.Equal(t, tenantMappingModel, result) 166 }) 167 168 t.Run("Error when get", func(t *testing.T) { 169 // GIVEN 170 db, dbMock := testdb.MockDatabase(t) 171 defer dbMock.AssertExpectations(t) 172 173 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 174 WithArgs(testID, tenantEntity.Inactive).WillReturnError(testError) 175 176 ctx := persistence.SaveToContext(context.TODO(), db) 177 tenantMappingRepo := tenant.NewRepository(nil) 178 179 // WHEN 180 result, err := tenantMappingRepo.Get(ctx, testID) 181 182 // THEN 183 require.Error(t, err) 184 require.Nil(t, result) 185 }) 186 } 187 188 func TestPgRepository_GetByExternalTenant(t *testing.T) { 189 t.Run("Success", func(t *testing.T) { 190 // GIVEN 191 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 192 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 193 194 mockConverter := &automock.Converter{} 195 defer mockConverter.AssertExpectations(t) 196 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 197 db, dbMock := testdb.MockDatabase(t) 198 defer dbMock.AssertExpectations(t) 199 rowsToReturn := fixSQLRows([]sqlRow{ 200 {id: testID, name: testName, externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 201 }) 202 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 203 WithArgs(testExternal, tenantEntity.Inactive). 204 WillReturnRows(rowsToReturn) 205 206 ctx := persistence.SaveToContext(context.TODO(), db) 207 tenantMappingRepo := tenant.NewRepository(mockConverter) 208 209 // WHEN 210 result, err := tenantMappingRepo.GetByExternalTenant(ctx, testExternal) 211 212 // THEN 213 require.NoError(t, err) 214 require.NotNil(t, result) 215 assert.Equal(t, tenantMappingModel, result) 216 }) 217 218 t.Run("Error when getting", func(t *testing.T) { 219 // GIVEN 220 mockConverter := &automock.Converter{} 221 defer mockConverter.AssertExpectations(t) 222 db, dbMock := testdb.MockDatabase(t) 223 defer dbMock.AssertExpectations(t) 224 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $ `)). 225 WithArgs(testExternal, tenantEntity.Inactive). 226 WillReturnError(testError) 227 228 ctx := persistence.SaveToContext(context.TODO(), db) 229 tenantMappingRepo := tenant.NewRepository(mockConverter) 230 231 // WHEN 232 result, err := tenantMappingRepo.GetByExternalTenant(ctx, testExternal) 233 234 // THEN 235 require.Error(t, err) 236 assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 237 require.Nil(t, result) 238 }) 239 } 240 241 func TestPgRepository_Exists(t *testing.T) { 242 t.Run("Success", func(t *testing.T) { 243 // GIVEN 244 db, dbMock := testdb.MockDatabase(t) 245 defer dbMock.AssertExpectations(t) 246 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT 1 FROM public.business_tenant_mappings WHERE id = $1`)). 247 WithArgs(testID). 248 WillReturnRows(testdb.RowWhenObjectExist()) 249 250 ctx := persistence.SaveToContext(context.TODO(), db) 251 tenantMappingRepo := tenant.NewRepository(nil) 252 253 // WHEN 254 result, err := tenantMappingRepo.Exists(ctx, testID) 255 256 // THEN 257 require.NoError(t, err) 258 require.NotNil(t, result) 259 assert.True(t, result) 260 }) 261 262 t.Run("Error when checking existence", func(t *testing.T) { 263 // GIVEN 264 db, dbMock := testdb.MockDatabase(t) 265 defer dbMock.AssertExpectations(t) 266 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT 1 FROM public.business_tenant_mappings WHERE id = $1`)). 267 WithArgs(testID). 268 WillReturnError(testError) 269 270 ctx := persistence.SaveToContext(context.TODO(), db) 271 tenantMappingRepo := tenant.NewRepository(nil) 272 273 // WHEN 274 result, err := tenantMappingRepo.Exists(ctx, testID) 275 276 // THEN 277 require.Error(t, err) 278 assert.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 279 assert.False(t, result) 280 }) 281 } 282 283 func TestPgRepository_ExistsByExternalTenant(t *testing.T) { 284 t.Run("Success", func(t *testing.T) { 285 // GIVEN 286 db, dbMock := testdb.MockDatabase(t) 287 defer dbMock.AssertExpectations(t) 288 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT 1 FROM public.business_tenant_mappings WHERE external_tenant = $1`)). 289 WithArgs(testExternal). 290 WillReturnRows(testdb.RowWhenObjectExist()) 291 292 ctx := persistence.SaveToContext(context.TODO(), db) 293 tenantMappingRepo := tenant.NewRepository(nil) 294 295 // WHEN 296 result, err := tenantMappingRepo.ExistsByExternalTenant(ctx, testExternal) 297 298 // THEN 299 require.NoError(t, err) 300 require.NotNil(t, result) 301 assert.True(t, result) 302 }) 303 304 t.Run("Error when checking existence", func(t *testing.T) { 305 // GIVEN 306 db, dbMock := testdb.MockDatabase(t) 307 defer dbMock.AssertExpectations(t) 308 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT 1 FROM public.business_tenant_mappings WHERE external_tenant = $1`)). 309 WithArgs(testExternal). 310 WillReturnError(testError) 311 312 ctx := persistence.SaveToContext(context.TODO(), db) 313 tenantMappingRepo := tenant.NewRepository(nil) 314 315 // WHEN 316 result, err := tenantMappingRepo.ExistsByExternalTenant(ctx, testExternal) 317 318 // THEN 319 require.Error(t, err) 320 assert.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 321 assert.False(t, result) 322 }) 323 } 324 325 func TestPgRepository_List(t *testing.T) { 326 t.Run("Success", func(t *testing.T) { 327 // GIVEN 328 329 initializedVal := true 330 notInitializedVal := false 331 332 tenantModels := []*model.BusinessTenantMapping{ 333 newModelBusinessTenantMappingWithComputedValues("id1", "name1", &initializedVal), 334 newModelBusinessTenantMappingWithComputedValues("id2", "name2", ¬InitializedVal), 335 newModelBusinessTenantMappingWithComputedValues("id3", "name3", ¬InitializedVal), 336 } 337 338 tenantEntities := []*tenantEntity.Entity{ 339 newEntityBusinessTenantMappingWithComputedValues("id1", "name1", &initializedVal), 340 newEntityBusinessTenantMappingWithComputedValues("id2", "name2", ¬InitializedVal), 341 newEntityBusinessTenantMappingWithComputedValues("id3", "name3", ¬InitializedVal), 342 } 343 344 mockConverter := &automock.Converter{} 345 defer mockConverter.AssertExpectations(t) 346 mockConverter.On("FromEntity", tenantEntities[0]).Return(tenantModels[0]).Once() 347 mockConverter.On("FromEntity", tenantEntities[1]).Return(tenantModels[1]).Once() 348 mockConverter.On("FromEntity", tenantEntities[2]).Return(tenantModels[2]).Once() 349 db, dbMock := testdb.MockDatabase(t) 350 defer dbMock.AssertExpectations(t) 351 352 rowsToReturn := fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{ 353 {sqlRow: sqlRow{id: "id1", name: "name1", externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: &initializedVal}, 354 {sqlRow: sqlRow{id: "id2", name: "name2", externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: ¬InitializedVal}, 355 {sqlRow: sqlRow{id: "id3", name: "name3", externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: ¬InitializedVal}, 356 }) 357 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT DISTINCT t.id, t.external_name, t.external_tenant, t.parent, t.type, t.provider_name, t.status, ld.tenant_id IS NOT NULL AS initialized FROM public.business_tenant_mappings t LEFT JOIN public.label_definitions ld ON t.id=ld.tenant_id WHERE t.status = $1 ORDER BY initialized DESC, t.external_name ASC`)). 358 WithArgs(tenantEntity.Active). 359 WillReturnRows(rowsToReturn) 360 361 ctx := persistence.SaveToContext(context.TODO(), db) 362 tenantMappingRepo := tenant.NewRepository(mockConverter) 363 364 // WHEN 365 result, err := tenantMappingRepo.List(ctx) 366 367 // THEN 368 require.NoError(t, err) 369 require.NotNil(t, result) 370 assert.Equal(t, tenantModels, result) 371 }) 372 373 t.Run("Error when listing", func(t *testing.T) { 374 // GIVEN 375 mockConverter := &automock.Converter{} 376 defer mockConverter.AssertExpectations(t) 377 db, dbMock := testdb.MockDatabase(t) 378 defer dbMock.AssertExpectations(t) 379 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT DISTINCT t.id, t.external_name, t.external_tenant, t.parent, t.type, t.provider_name, t.status, ld.tenant_id IS NOT NULL AS initialized FROM public.business_tenant_mappings t LEFT JOIN public.label_definitions ld ON t.id=ld.tenant_id WHERE t.status = $1 ORDER BY initialized DESC, t.external_name ASC`)). 380 WithArgs(tenantEntity.Active). 381 WillReturnError(testError) 382 383 ctx := persistence.SaveToContext(context.TODO(), db) 384 tenantMappingRepo := tenant.NewRepository(mockConverter) 385 386 // WHEN 387 result, err := tenantMappingRepo.List(ctx) 388 389 // THEN 390 require.Error(t, err) 391 assert.Contains(t, err.Error(), testError.Error()) 392 require.Nil(t, result) 393 }) 394 395 t.Run("Error when missing persistence context", func(t *testing.T) { 396 // GIVEN 397 repo := tenant.NewRepository(nil) 398 ctx := context.TODO() 399 400 // WHEN 401 _, err := repo.List(ctx) 402 403 // THEN 404 require.EqualError(t, err, "while fetching persistence from context: Internal Server Error: unable to fetch database from context") 405 }) 406 } 407 408 func TestPgRepository_ListPageBySearchTerm(t *testing.T) { 409 t.Run("Success", func(t *testing.T) { 410 // GIVEN 411 searchTerm := "name" 412 first := 10 413 endCursor := "" 414 initializedVal := true 415 notInitializedVal := false 416 417 tenantModels := []*model.BusinessTenantMapping{ 418 newModelBusinessTenantMappingWithComputedValues("id1", "name1", &initializedVal), 419 newModelBusinessTenantMappingWithComputedValues("id2", "name2", ¬InitializedVal), 420 newModelBusinessTenantMappingWithComputedValues("id3", "name3", ¬InitializedVal), 421 } 422 423 tenantEntities := []*tenantEntity.Entity{ 424 newEntityBusinessTenantMappingWithComputedValues("id1", "name1", &initializedVal), 425 newEntityBusinessTenantMappingWithComputedValues("id2", "name2", ¬InitializedVal), 426 newEntityBusinessTenantMappingWithComputedValues("id3", "name3", ¬InitializedVal), 427 } 428 429 tenantPage := &model.BusinessTenantMappingPage{ 430 Data: tenantModels, 431 PageInfo: &pagination.Page{ 432 StartCursor: "", 433 EndCursor: "", 434 HasNextPage: false, 435 }, 436 TotalCount: len(tenantModels), 437 } 438 439 mockConverter := &automock.Converter{} 440 defer mockConverter.AssertExpectations(t) 441 mockConverter.On("FromEntity", tenantEntities[0]).Return(tenantModels[0]).Once() 442 mockConverter.On("FromEntity", tenantEntities[1]).Return(tenantModels[1]).Once() 443 mockConverter.On("FromEntity", tenantEntities[2]).Return(tenantModels[2]).Once() 444 db, dbMock := testdb.MockDatabase(t) 445 defer dbMock.AssertExpectations(t) 446 447 rowsToReturn := fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{ 448 {sqlRow: sqlRow{id: "id1", name: "name1", externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: &initializedVal}, 449 {sqlRow: sqlRow{id: "id2", name: "name2", externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: ¬InitializedVal}, 450 {sqlRow: sqlRow{id: "id3", name: "name3", externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: ¬InitializedVal}, 451 }) 452 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE (status = $1 AND (id::text ILIKE $2 OR external_name ILIKE $3 OR external_tenant ILIKE $4)) ORDER BY external_name LIMIT 10 OFFSET 0`)). 453 WithArgs(tenantEntity.Active, "%name%", "%name%", "%name%"). 454 WillReturnRows(rowsToReturn) 455 456 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM public.business_tenant_mappings WHERE (status = $1 AND (id::text ILIKE $2 OR external_name ILIKE $3 OR external_tenant ILIKE $4))`)). 457 WithArgs(tenantEntity.Active, "%name%", "%name%", "%name%"). 458 WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(3)) 459 460 ctx := persistence.SaveToContext(context.TODO(), db) 461 tenantMappingRepo := tenant.NewRepository(mockConverter) 462 463 // WHEN 464 result, err := tenantMappingRepo.ListPageBySearchTerm(ctx, searchTerm, first, endCursor) 465 466 // THEN 467 require.NoError(t, err) 468 require.NotNil(t, result) 469 assert.Equal(t, tenantPage, result) 470 }) 471 472 t.Run("Error when listing", func(t *testing.T) { 473 // GIVEN 474 searchTerm := "name" 475 first := 10 476 endCursor := "" 477 478 mockConverter := &automock.Converter{} 479 defer mockConverter.AssertExpectations(t) 480 db, dbMock := testdb.MockDatabase(t) 481 defer dbMock.AssertExpectations(t) 482 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE (status = $1 AND (id::text ILIKE $2 OR external_name ILIKE $3 OR external_tenant ILIKE $4)) ORDER BY external_name LIMIT 10 OFFSET 0`)). 483 WithArgs(tenantEntity.Active, "%name%", "%name%", "%name%"). 484 WillReturnError(testError) 485 486 ctx := persistence.SaveToContext(context.TODO(), db) 487 tenantMappingRepo := tenant.NewRepository(mockConverter) 488 489 // WHEN 490 result, err := tenantMappingRepo.ListPageBySearchTerm(ctx, searchTerm, first, endCursor) 491 492 // THEN 493 require.Error(t, err) 494 assert.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 495 require.Nil(t, result) 496 }) 497 498 t.Run("Error when missing persistence context", func(t *testing.T) { 499 // GIVEN 500 searchTerm := "name" 501 first := 10 502 endCursor := "" 503 repo := tenant.NewRepository(nil) 504 ctx := context.TODO() 505 506 // WHEN 507 _, err := repo.ListPageBySearchTerm(ctx, searchTerm, first, endCursor) 508 509 // THEN 510 require.EqualError(t, err, "while listing tenants from DB: Internal Server Error: unable to fetch database from context") 511 }) 512 } 513 514 func TestPgRepository_ListByExternalTenants(t *testing.T) { 515 t.Run("Success", func(t *testing.T) { 516 // GIVEN 517 initializedVal := true 518 tntModel := &model.BusinessTenantMapping{ID: id(), ExternalTenant: id(), Initialized: &initializedVal} 519 tntEntity := &tenantEntity.Entity{ID: tntModel.ID, ExternalTenant: tntModel.ExternalTenant, Initialized: &initializedVal} 520 521 mockConverter := &automock.Converter{} 522 defer mockConverter.AssertExpectations(t) 523 mockConverter.On("FromEntity", tntEntity).Return(tntModel).Once() 524 db, dbMock := testdb.MockDatabase(t) 525 defer dbMock.AssertExpectations(t) 526 527 rowsToReturn := fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{{sqlRow: sqlRow{id: tntModel.ID, externalTenant: tntModel.ExternalTenant}, initialized: &initializedVal}}) 528 529 query := `SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant IN ($1)` 530 531 dbMock.ExpectQuery(regexp.QuoteMeta(query)). 532 WithArgs(tntModel.ExternalTenant). 533 WillReturnRows(rowsToReturn) 534 535 ctx := persistence.SaveToContext(context.TODO(), db) 536 tenantMappingRepo := tenant.NewRepository(mockConverter) 537 538 // WHEN 539 result, err := tenantMappingRepo.ListByExternalTenants(ctx, []string{tntModel.ExternalTenant}) 540 541 // THEN 542 require.NoError(t, err) 543 require.NotNil(t, result) 544 assert.Equal(t, []*model.BusinessTenantMapping{tntModel}, result) 545 }) 546 547 t.Run("Success when high load of tenants is requested", func(t *testing.T) { 548 // GIVEN 549 initializedVal := true 550 tntModel := &model.BusinessTenantMapping{ID: id(), ExternalTenant: id(), Initialized: &initializedVal} 551 tntEntity := &tenantEntity.Entity{ID: tntModel.ID, ExternalTenant: tntModel.ExternalTenant, Initialized: &initializedVal} 552 553 mockConverter := &automock.Converter{} 554 defer mockConverter.AssertExpectations(t) 555 mockConverter.On("FromEntity", tntEntity).Return(tntModel).Once() 556 db, dbMock := testdb.MockDatabase(t) 557 defer dbMock.AssertExpectations(t) 558 559 rowsToReturn := fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{{sqlRow: sqlRow{id: tntModel.ID, externalTenant: tntModel.ExternalTenant}, initialized: &initializedVal}}) 560 561 // get first chunk of tenant IDs 562 firstChunkIDs := chunkSizedTenantIDs(49999) 563 firstChunkIDs = append(firstChunkIDs, tntModel.ExternalTenant) 564 firstChunkQuery, firstChunkQueryArgs := buildQueryWithTenantIDs(firstChunkIDs) 565 dbMock.ExpectQuery(regexp.QuoteMeta(firstChunkQuery)). 566 WithArgs(firstChunkQueryArgs...). 567 WillReturnRows(rowsToReturn) 568 569 // get second chunk of tenant IDs 570 secondChunkIDs := chunkSizedTenantIDs(100) 571 secondChunkQuery, secondChunkIDsChunkQueryArgs := buildQueryWithTenantIDs(secondChunkIDs) 572 dbMock.ExpectQuery(regexp.QuoteMeta(secondChunkQuery)). 573 WithArgs(secondChunkIDsChunkQueryArgs...). 574 WillReturnRows(fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{})) 575 576 ctx := persistence.SaveToContext(context.TODO(), db) 577 tenantMappingRepo := tenant.NewRepository(mockConverter) 578 579 // WHEN 580 result, err := tenantMappingRepo.ListByExternalTenants(ctx, append(firstChunkIDs, secondChunkIDs...)) 581 582 // THEN 583 require.NoError(t, err) 584 require.NotNil(t, result) 585 assert.Equal(t, []*model.BusinessTenantMapping{tntModel}, result) 586 }) 587 588 t.Run("Error when listing", func(t *testing.T) { 589 // GIVEN 590 externalTenantID := id() 591 592 mockConverter := &automock.Converter{} 593 defer mockConverter.AssertExpectations(t) 594 db, dbMock := testdb.MockDatabase(t) 595 defer dbMock.AssertExpectations(t) 596 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant IN ($1)`)). 597 WithArgs(externalTenantID). 598 WillReturnError(testError) 599 600 ctx := persistence.SaveToContext(context.TODO(), db) 601 tenantMappingRepo := tenant.NewRepository(mockConverter) 602 603 // WHEN 604 result, err := tenantMappingRepo.ListByExternalTenants(ctx, []string{externalTenantID}) 605 606 // THEN 607 require.Error(t, err) 608 assert.Contains(t, err.Error(), "Unexpected error while executing SQL query") 609 require.Nil(t, result) 610 }) 611 612 t.Run("Error when missing persistence context", func(t *testing.T) { 613 // GIVEN 614 repo := tenant.NewRepository(nil) 615 ctx := context.TODO() 616 617 // WHEN 618 _, err := repo.ListByExternalTenants(ctx, []string{id()}) 619 620 // THEN 621 require.EqualError(t, err, "Internal Server Error: unable to fetch database from context") 622 }) 623 } 624 625 func TestPgRepository_ListByParentAndType(t *testing.T) { 626 t.Run("Success", func(t *testing.T) { 627 // GIVEN 628 parentID := "test" 629 630 resultTntModel := []*model.BusinessTenantMapping{ 631 newModelBusinessTenantMappingWithParentAndType("id1", "name1", parentID, nil, tenantEntity.Account), 632 } 633 634 tntEntity := newEntityBusinessTenantMappingWithParentAndAccount("id1", "name1", parentID, tenantEntity.Account) 635 tntEntity.Initialized = boolToPtr(true) 636 637 mockConverter := &automock.Converter{} 638 mockConverter.On("FromEntity", tntEntity).Return(resultTntModel[0]).Once() 639 defer mockConverter.AssertExpectations(t) 640 641 db, dbMock := testdb.MockDatabase(t) 642 defer dbMock.AssertExpectations(t) 643 644 rowsToReturn := fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{ 645 {sqlRow: sqlRow{id: "id1", name: "name1", externalTenant: testExternal, parent: str.NewNullString(parentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: boolToPtr(true)}, 646 }) 647 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE parent = $1 AND type = $2`)). 648 WithArgs(parentID, tenantEntity.Account). 649 WillReturnRows(rowsToReturn) 650 651 ctx := persistence.SaveToContext(context.TODO(), db) 652 tenantMappingRepo := tenant.NewRepository(mockConverter) 653 654 // WHEN 655 result, err := tenantMappingRepo.ListByParentAndType(ctx, parentID, tenantEntity.Account) 656 657 // THEN 658 require.NoError(t, err) 659 require.NotNil(t, result) 660 assert.Equal(t, resultTntModel, result) 661 }) 662 663 t.Run("Error when listing", func(t *testing.T) { 664 // GIVEN 665 parentID := "test" 666 667 tntEntity := newEntityBusinessTenantMappingWithParentAndAccount("id1", "name1", parentID, tenantEntity.Account) 668 tntEntity.Initialized = boolToPtr(true) 669 670 mockConverter := &automock.Converter{} 671 defer mockConverter.AssertExpectations(t) 672 673 db, dbMock := testdb.MockDatabase(t) 674 defer dbMock.AssertExpectations(t) 675 676 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE parent = $1 AND type = $2`)). 677 WithArgs(parentID, tenantEntity.Account). 678 WillReturnError(testError) 679 680 ctx := persistence.SaveToContext(context.TODO(), db) 681 tenantMappingRepo := tenant.NewRepository(mockConverter) 682 683 // WHEN 684 result, err := tenantMappingRepo.ListByParentAndType(ctx, parentID, tenantEntity.Account) 685 686 // THEN 687 require.Error(t, err) 688 assert.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 689 require.Nil(t, result) 690 }) 691 692 t.Run("Error when missing persistence context", func(t *testing.T) { 693 // GIVEN 694 parentID := "test" 695 repo := tenant.NewRepository(nil) 696 ctx := context.TODO() 697 698 // WHEN 699 result, err := repo.ListByParentAndType(ctx, parentID, tenantEntity.Account) 700 701 // THEN 702 require.EqualError(t, err, "Internal Server Error: unable to fetch database from context") 703 assert.Nil(t, result) 704 }) 705 } 706 707 func TestPgRepository_ListByType(t *testing.T) { 708 t.Run("Success", func(t *testing.T) { 709 // GIVEN 710 parentID := "test" 711 712 resultTntModel := []*model.BusinessTenantMapping{ 713 newModelBusinessTenantMappingWithParentAndType("id1", "name1", parentID, nil, tenantEntity.Account), 714 } 715 716 tntEntity := newEntityBusinessTenantMappingWithParentAndAccount("id1", "name1", parentID, tenantEntity.Account) 717 tntEntity.Initialized = boolToPtr(true) 718 719 mockConverter := &automock.Converter{} 720 mockConverter.On("FromEntity", tntEntity).Return(resultTntModel[0]).Once() 721 defer mockConverter.AssertExpectations(t) 722 723 db, dbMock := testdb.MockDatabase(t) 724 defer dbMock.AssertExpectations(t) 725 726 rowsToReturn := fixSQLRowsWithComputedValues([]sqlRowWithComputedValues{ 727 {sqlRow: sqlRow{id: "id1", name: "name1", externalTenant: testExternal, parent: str.NewNullString(parentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, initialized: boolToPtr(true)}, 728 }) 729 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE type = $1`)). 730 WithArgs(tenantEntity.Account). 731 WillReturnRows(rowsToReturn) 732 733 ctx := persistence.SaveToContext(context.TODO(), db) 734 tenantMappingRepo := tenant.NewRepository(mockConverter) 735 736 // WHEN 737 result, err := tenantMappingRepo.ListByType(ctx, tenantEntity.Account) 738 739 // THEN 740 require.NoError(t, err) 741 require.NotNil(t, result) 742 assert.Equal(t, resultTntModel, result) 743 }) 744 745 t.Run("Error when listing", func(t *testing.T) { 746 // GIVEN 747 parentID := "test" 748 749 tntEntity := newEntityBusinessTenantMappingWithParentAndAccount("id1", "name1", parentID, tenantEntity.Account) 750 tntEntity.Initialized = boolToPtr(true) 751 752 mockConverter := &automock.Converter{} 753 defer mockConverter.AssertExpectations(t) 754 755 db, dbMock := testdb.MockDatabase(t) 756 defer dbMock.AssertExpectations(t) 757 758 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE type = $1`)). 759 WithArgs(tenantEntity.Account). 760 WillReturnError(testError) 761 762 ctx := persistence.SaveToContext(context.TODO(), db) 763 tenantMappingRepo := tenant.NewRepository(mockConverter) 764 765 // WHEN 766 result, err := tenantMappingRepo.ListByType(ctx, tenantEntity.Account) 767 768 // THEN 769 require.Error(t, err) 770 assert.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 771 require.Nil(t, result) 772 }) 773 774 t.Run("Error when missing persistence context", func(t *testing.T) { 775 // GIVEN 776 repo := tenant.NewRepository(nil) 777 ctx := context.TODO() 778 779 // WHEN 780 result, err := repo.ListByType(ctx, tenantEntity.Account) 781 782 // THEN 783 require.EqualError(t, err, "Internal Server Error: unable to fetch database from context") 784 assert.Nil(t, result) 785 }) 786 } 787 func buildQueryWithTenantIDs(ids []string) (string, []driver.Value) { 788 argumentValues := make([]driver.Value, 0) 789 var sb strings.Builder 790 for i, id := range ids { 791 argumentValues = append(argumentValues, id) 792 sb.WriteString(fmt.Sprintf("$%d", i+1)) 793 if i < len(ids)-1 { 794 sb.WriteString(", ") 795 } 796 } 797 798 queryFormat := `SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant IN (%s)` 799 query := fmt.Sprintf(queryFormat, sb.String()) 800 801 return query, argumentValues 802 } 803 804 func chunkSizedTenantIDs(chunkSize int) []string { 805 ids := make([]string, chunkSize) 806 for i := 0; i < chunkSize; i++ { 807 ids[i] = id() 808 } 809 return ids 810 } 811 812 func TestPgRepository_Update(t *testing.T) { 813 t.Run("Success", func(t *testing.T) { 814 // GIVEN 815 tenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 816 tenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID) 817 818 mockConverter := &automock.Converter{} 819 mockConverter.On("ToEntity", tenantMappingModel).Return(tenantMappingEntity).Once() 820 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 821 822 db, dbMock := testdb.MockDatabase(t) 823 824 rowsToReturn := fixSQLRows([]sqlRow{ 825 {id: testID, name: testName, externalTenant: testExternal, parent: repo.NewValidNullableString(testParentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 826 }) 827 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 828 WithArgs(testID, tenantEntity.Inactive). 829 WillReturnRows(rowsToReturn) 830 831 dbMock.ExpectExec(regexp.QuoteMeta(`UPDATE public.business_tenant_mappings SET external_name = ?, external_tenant = ?, parent = ?, type = ?, provider_name = ?, status = ? WHERE id = ? `)). 832 WithArgs(testName, testExternal, testParentID, "account", "Compass", tenantEntity.Active, testID). 833 WillReturnResult(sqlmock.NewResult(-1, 1)) 834 835 ctx := persistence.SaveToContext(context.TODO(), db) 836 tenantMappingRepo := tenant.NewRepository(mockConverter) 837 838 // WHEN 839 err := tenantMappingRepo.Update(ctx, tenantMappingModel) 840 841 // THEN 842 require.NoError(t, err) 843 mockConverter.AssertExpectations(t) 844 dbMock.AssertExpectations(t) 845 }) 846 847 t.Run("Error when getting", func(t *testing.T) { 848 // GIVEN 849 tenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 850 851 db, dbMock := testdb.MockDatabase(t) 852 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 853 WithArgs(testID, tenantEntity.Inactive). 854 WillReturnError(testError) 855 856 ctx := persistence.SaveToContext(context.TODO(), db) 857 tenantMappingRepo := tenant.NewRepository(nil) 858 859 // WHEN 860 err := tenantMappingRepo.Update(ctx, tenantMappingModel) 861 862 // THEN 863 require.Error(t, err) 864 assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 865 dbMock.AssertExpectations(t) 866 }) 867 868 t.Run("Error when updating", func(t *testing.T) { 869 // GIVEN 870 tenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 871 tenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID) 872 873 mockConverter := &automock.Converter{} 874 mockConverter.On("ToEntity", tenantMappingModel).Return(tenantMappingEntity).Once() 875 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 876 877 db, dbMock := testdb.MockDatabase(t) 878 879 rowsToReturn := fixSQLRows([]sqlRow{ 880 {id: testID, name: testName, externalTenant: testExternal, parent: repo.NewValidNullableString(testParentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 881 }) 882 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 883 WithArgs(testID, tenantEntity.Inactive). 884 WillReturnRows(rowsToReturn) 885 886 dbMock.ExpectExec(regexp.QuoteMeta(`UPDATE public.business_tenant_mappings SET external_name = ?, external_tenant = ?, parent = ?, type = ?, provider_name = ?, status = ? WHERE id = ? `)). 887 WithArgs(testName, testExternal, testParentID, "account", "Compass", tenantEntity.Active, testID). 888 WillReturnError(testError) 889 890 ctx := persistence.SaveToContext(context.TODO(), db) 891 tenantMappingRepo := tenant.NewRepository(mockConverter) 892 893 // WHEN 894 err := tenantMappingRepo.Update(ctx, tenantMappingModel) 895 896 // THEN 897 require.Error(t, err) 898 assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 899 mockConverter.AssertExpectations(t) 900 dbMock.AssertExpectations(t) 901 }) 902 903 t.Run("Success when parent is updated", func(t *testing.T) { 904 // GIVEN 905 oldTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 906 newTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID2, nil, tenantEntity.Account) 907 oldTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID) 908 newTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID2) 909 910 mockConverter := &automock.Converter{} 911 mockConverter.On("ToEntity", newTenantMappingModel).Return(newTenantMappingEntity).Once() 912 mockConverter.On("FromEntity", oldTenantMappingEntity).Return(oldTenantMappingModel).Once() 913 914 db, dbMock := testdb.MockDatabase(t) 915 916 rowsToReturn := fixSQLRows([]sqlRow{ 917 {id: testID, name: testName, externalTenant: testExternal, parent: repo.NewValidNullableString(testParentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 918 }) 919 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 920 WithArgs(testID, tenantEntity.Inactive). 921 WillReturnRows(rowsToReturn) 922 923 dbMock.ExpectExec(regexp.QuoteMeta(`UPDATE public.business_tenant_mappings SET external_name = ?, external_tenant = ?, parent = ?, type = ?, provider_name = ?, status = ? WHERE id = ? `)). 924 WithArgs(testName, testExternal, testParentID2, "account", "Compass", tenantEntity.Active, testID). 925 WillReturnResult(sqlmock.NewResult(-1, 1)) 926 927 for topLvlEntity := range resource.TopLevelEntities { 928 if _, ok := topLvlEntity.IgnoredTenantAccessTable(); ok { 929 continue 930 } 931 tenantAccesses := fixTenantAccesses() 932 933 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 934 WithArgs(testID, true).WillReturnRows(sqlmock.NewRows(repo.M2MColumns).AddRow(fixTenantAccessesRow()...)) 935 936 dbMock.ExpectExec(`WITH RECURSIVE parents AS \(SELECT t1\.id, t1\.parent FROM business_tenant_mappings t1 WHERE id = \? UNION ALL SELECT t2\.id, t2\.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2\.id = t\.parent\) INSERT INTO (.+) \( tenant_id, id, owner \) \(SELECT parents\.id AS tenant_id, \? as id, \? AS owner FROM parents\)`). 937 WithArgs(testParentID2, tenantAccesses[0].ResourceID, true).WillReturnResult(sqlmock.NewResult(-1, 1)) 938 939 dbMock.ExpectExec(`WITH RECURSIVE parents AS \(SELECT t1\.id, t1\.parent FROM business_tenant_mappings t1 WHERE id = \$1 UNION ALL SELECT t2\.id, t2\.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2\.id = t\.parent\) DELETE FROM (.+) WHERE id IN \(\$2\) AND tenant_id IN \(SELECT id FROM parents\)`). 940 WithArgs(testParentID, tenantAccesses[0].ResourceID).WillReturnResult(sqlmock.NewResult(-1, 1)) 941 } 942 943 ctx := persistence.SaveToContext(context.TODO(), db) 944 tenantMappingRepo := tenant.NewRepository(mockConverter) 945 946 // WHEN 947 err := tenantMappingRepo.Update(ctx, newTenantMappingModel) 948 949 // THEN 950 require.NoError(t, err) 951 mockConverter.AssertExpectations(t) 952 dbMock.AssertExpectations(t) 953 }) 954 955 t.Run("Error when parent is updated and list tenant accesses fail", func(t *testing.T) { 956 // GIVEN 957 oldTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 958 newTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID2, nil, tenantEntity.Account) 959 oldTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID) 960 newTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID2) 961 962 mockConverter := &automock.Converter{} 963 mockConverter.On("ToEntity", newTenantMappingModel).Return(newTenantMappingEntity).Once() 964 mockConverter.On("FromEntity", oldTenantMappingEntity).Return(oldTenantMappingModel).Once() 965 966 db, dbMock := testdb.MockDatabase(t) 967 968 rowsToReturn := fixSQLRows([]sqlRow{ 969 {id: testID, name: testName, externalTenant: testExternal, parent: repo.NewValidNullableString(testParentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 970 }) 971 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 972 WithArgs(testID, tenantEntity.Inactive). 973 WillReturnRows(rowsToReturn) 974 975 dbMock.ExpectExec(regexp.QuoteMeta(`UPDATE public.business_tenant_mappings SET external_name = ?, external_tenant = ?, parent = ?, type = ?, provider_name = ?, status = ? WHERE id = ? `)). 976 WithArgs(testName, testExternal, testParentID2, "account", "Compass", tenantEntity.Active, testID). 977 WillReturnResult(sqlmock.NewResult(-1, 1)) 978 979 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 980 WithArgs(testID, true).WillReturnError(testError) 981 982 ctx := persistence.SaveToContext(context.TODO(), db) 983 tenantMappingRepo := tenant.NewRepository(mockConverter) 984 985 // WHEN 986 err := tenantMappingRepo.Update(ctx, newTenantMappingModel) 987 988 // THEN 989 require.Error(t, err) 990 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 991 mockConverter.AssertExpectations(t) 992 dbMock.AssertExpectations(t) 993 }) 994 995 t.Run("Error when parent is updated and create tenant access fail", func(t *testing.T) { 996 // GIVEN 997 oldTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 998 newTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID2, nil, tenantEntity.Account) 999 oldTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID) 1000 newTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID2) 1001 1002 mockConverter := &automock.Converter{} 1003 mockConverter.On("ToEntity", newTenantMappingModel).Return(newTenantMappingEntity).Once() 1004 mockConverter.On("FromEntity", oldTenantMappingEntity).Return(oldTenantMappingModel).Once() 1005 1006 db, dbMock := testdb.MockDatabase(t) 1007 1008 rowsToReturn := fixSQLRows([]sqlRow{ 1009 {id: testID, name: testName, externalTenant: testExternal, parent: repo.NewValidNullableString(testParentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 1010 }) 1011 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 1012 WithArgs(testID, tenantEntity.Inactive). 1013 WillReturnRows(rowsToReturn) 1014 1015 dbMock.ExpectExec(regexp.QuoteMeta(`UPDATE public.business_tenant_mappings SET external_name = ?, external_tenant = ?, parent = ?, type = ?, provider_name = ?, status = ? WHERE id = ? `)). 1016 WithArgs(testName, testExternal, testParentID2, "account", "Compass", tenantEntity.Active, testID). 1017 WillReturnResult(sqlmock.NewResult(-1, 1)) 1018 1019 appTenantAccesses := fixTenantAccesses() 1020 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 1021 WithArgs(testID, true).WillReturnRows(sqlmock.NewRows(repo.M2MColumns).AddRow(fixTenantAccessesRow()...)) 1022 1023 dbMock.ExpectExec(`WITH RECURSIVE parents AS \(SELECT t1\.id, t1\.parent FROM business_tenant_mappings t1 WHERE id = \? UNION ALL SELECT t2\.id, t2\.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2\.id = t\.parent\) INSERT INTO (.+) \( tenant_id, id, owner \) \(SELECT parents\.id AS tenant_id, \? as id, \? AS owner FROM parents\)`). 1024 WithArgs(testParentID2, appTenantAccesses[0].ResourceID, true).WillReturnError(testError) 1025 1026 ctx := persistence.SaveToContext(context.TODO(), db) 1027 tenantMappingRepo := tenant.NewRepository(mockConverter) 1028 1029 // WHEN 1030 err := tenantMappingRepo.Update(ctx, newTenantMappingModel) 1031 1032 // THEN 1033 require.Error(t, err) 1034 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 1035 mockConverter.AssertExpectations(t) 1036 dbMock.AssertExpectations(t) 1037 }) 1038 1039 t.Run("Error when parent is updated and tenant access delete fail", func(t *testing.T) { 1040 // GIVEN 1041 oldTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID, nil, tenantEntity.Account) 1042 newTenantMappingModel := newModelBusinessTenantMappingWithType(testID, testName, testParentID2, nil, tenantEntity.Account) 1043 oldTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID) 1044 newTenantMappingEntity := newEntityBusinessTenantMappingWithParent(testID, testName, testParentID2) 1045 1046 mockConverter := &automock.Converter{} 1047 mockConverter.On("ToEntity", newTenantMappingModel).Return(newTenantMappingEntity).Once() 1048 mockConverter.On("FromEntity", oldTenantMappingEntity).Return(oldTenantMappingModel).Once() 1049 1050 db, dbMock := testdb.MockDatabase(t) 1051 1052 rowsToReturn := fixSQLRows([]sqlRow{ 1053 {id: testID, name: testName, externalTenant: testExternal, parent: repo.NewValidNullableString(testParentID), typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 1054 }) 1055 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE id = $1 AND status != $2 `)). 1056 WithArgs(testID, tenantEntity.Inactive). 1057 WillReturnRows(rowsToReturn) 1058 1059 dbMock.ExpectExec(regexp.QuoteMeta(`UPDATE public.business_tenant_mappings SET external_name = ?, external_tenant = ?, parent = ?, type = ?, provider_name = ?, status = ? WHERE id = ? `)). 1060 WithArgs(testName, testExternal, testParentID2, "account", "Compass", tenantEntity.Active, testID). 1061 WillReturnResult(sqlmock.NewResult(-1, 1)) 1062 1063 appTenantAccesses := fixTenantAccesses() 1064 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 1065 WithArgs(testID, true).WillReturnRows(sqlmock.NewRows(repo.M2MColumns).AddRow(fixTenantAccessesRow()...)) 1066 1067 dbMock.ExpectExec(`WITH RECURSIVE parents AS \(SELECT t1\.id, t1\.parent FROM business_tenant_mappings t1 WHERE id = \? UNION ALL SELECT t2\.id, t2\.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2\.id = t\.parent\) INSERT INTO (.+) \( tenant_id, id, owner \) \(SELECT parents\.id AS tenant_id, \? as id, \? AS owner FROM parents\)`). 1068 WithArgs(testParentID2, appTenantAccesses[0].ResourceID, true).WillReturnResult(sqlmock.NewResult(-1, 1)) 1069 1070 dbMock.ExpectExec(`WITH RECURSIVE parents AS \(SELECT t1\.id, t1\.parent FROM business_tenant_mappings t1 WHERE id = \$1 UNION ALL SELECT t2\.id, t2\.parent FROM business_tenant_mappings t2 INNER JOIN parents t on t2\.id = t\.parent\) DELETE FROM (.+) WHERE id IN \(\$2\) AND tenant_id IN \(SELECT id FROM parents\)`). 1071 WithArgs(testParentID, appTenantAccesses[0].ResourceID).WillReturnError(testError) 1072 1073 ctx := persistence.SaveToContext(context.TODO(), db) 1074 tenantMappingRepo := tenant.NewRepository(mockConverter) 1075 1076 // WHEN 1077 err := tenantMappingRepo.Update(ctx, newTenantMappingModel) 1078 1079 // THEN 1080 require.Error(t, err) 1081 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 1082 mockConverter.AssertExpectations(t) 1083 dbMock.AssertExpectations(t) 1084 }) 1085 } 1086 1087 func TestPgRepository_DeleteByExternalTenant(t *testing.T) { 1088 deleteStatement := regexp.QuoteMeta(`DELETE FROM public.business_tenant_mappings WHERE external_tenant = $1`) 1089 1090 t.Run("Success", func(t *testing.T) { 1091 // GIVEN 1092 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 1093 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 1094 1095 mockConverter := &automock.Converter{} 1096 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 1097 1098 db, dbMock := testdb.MockDatabase(t) 1099 rowsToReturn := fixSQLRows([]sqlRow{ 1100 {id: testID, name: testName, externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 1101 }) 1102 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 1103 WithArgs(testExternal, tenantEntity.Inactive). 1104 WillReturnRows(rowsToReturn) 1105 1106 for topLvlEntity := range resource.TopLevelEntities { 1107 if _, ok := topLvlEntity.IgnoredTenantAccessTable(); ok { 1108 continue 1109 } 1110 tenantAccesses := fixTenantAccesses() 1111 1112 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 1113 WithArgs(testID, true).WillReturnRows(sqlmock.NewRows(repo.M2MColumns).AddRow(fixTenantAccessesRow()...)) 1114 1115 dbMock.ExpectExec(`DELETE FROM (.+) WHERE id IN \(\$1\)`). 1116 WithArgs(tenantAccesses[0].ResourceID).WillReturnResult(sqlmock.NewResult(-1, 1)) 1117 } 1118 1119 dbMock.ExpectExec(deleteStatement). 1120 WithArgs(testExternal). 1121 WillReturnResult(sqlmock.NewResult(-1, 1)) 1122 1123 ctx := persistence.SaveToContext(context.TODO(), db) 1124 repo := tenant.NewRepository(mockConverter) 1125 1126 // WHEN 1127 err := repo.DeleteByExternalTenant(ctx, testExternal) 1128 1129 // THEN 1130 require.NoError(t, err) 1131 dbMock.AssertExpectations(t) 1132 mockConverter.AssertExpectations(t) 1133 }) 1134 1135 t.Run("Success when getting tenant before delete returns not found", func(t *testing.T) { 1136 // GIVEN 1137 db, dbMock := testdb.MockDatabase(t) 1138 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 1139 WithArgs(testExternal, tenantEntity.Inactive). 1140 WillReturnError(sql.ErrNoRows) 1141 1142 ctx := persistence.SaveToContext(context.TODO(), db) 1143 repo := tenant.NewRepository(nil) 1144 1145 // WHEN 1146 err := repo.DeleteByExternalTenant(ctx, testExternal) 1147 1148 // THEN 1149 require.NoError(t, err) 1150 dbMock.AssertExpectations(t) 1151 }) 1152 1153 t.Run("Error when getting tenant before delete fail", func(t *testing.T) { 1154 // GIVEN 1155 db, dbMock := testdb.MockDatabase(t) 1156 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 1157 WithArgs(testExternal, tenantEntity.Inactive). 1158 WillReturnError(testError) 1159 1160 ctx := persistence.SaveToContext(context.TODO(), db) 1161 repo := tenant.NewRepository(nil) 1162 1163 // WHEN 1164 err := repo.DeleteByExternalTenant(ctx, testExternal) 1165 1166 // THEN 1167 require.Error(t, err) 1168 require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query") 1169 dbMock.AssertExpectations(t) 1170 }) 1171 1172 t.Run("Error when List tenant access fail", func(t *testing.T) { 1173 // GIVEN 1174 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 1175 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 1176 1177 mockConverter := &automock.Converter{} 1178 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 1179 1180 db, dbMock := testdb.MockDatabase(t) 1181 rowsToReturn := fixSQLRows([]sqlRow{ 1182 {id: testID, name: testName, externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 1183 }) 1184 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 1185 WithArgs(testExternal, tenantEntity.Inactive). 1186 WillReturnRows(rowsToReturn) 1187 1188 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 1189 WithArgs(testID, true).WillReturnError(testError) 1190 1191 ctx := persistence.SaveToContext(context.TODO(), db) 1192 repo := tenant.NewRepository(mockConverter) 1193 1194 // WHEN 1195 err := repo.DeleteByExternalTenant(ctx, testExternal) 1196 1197 // THEN 1198 require.Error(t, err) 1199 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 1200 dbMock.AssertExpectations(t) 1201 mockConverter.AssertExpectations(t) 1202 }) 1203 1204 t.Run("Error when Delete tenant access fail", func(t *testing.T) { 1205 // GIVEN 1206 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 1207 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 1208 1209 mockConverter := &automock.Converter{} 1210 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 1211 1212 db, dbMock := testdb.MockDatabase(t) 1213 rowsToReturn := fixSQLRows([]sqlRow{ 1214 {id: testID, name: testName, externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 1215 }) 1216 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 1217 WithArgs(testExternal, tenantEntity.Inactive). 1218 WillReturnRows(rowsToReturn) 1219 1220 appTenantAccesses := fixTenantAccesses() 1221 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 1222 WithArgs(testID, true).WillReturnRows(sqlmock.NewRows(repo.M2MColumns).AddRow(fixTenantAccessesRow()...)) 1223 1224 dbMock.ExpectExec(`DELETE FROM (.+) WHERE id IN \(\$1\)`). 1225 WithArgs(appTenantAccesses[0].ResourceID).WillReturnError(testError) 1226 1227 ctx := persistence.SaveToContext(context.TODO(), db) 1228 repo := tenant.NewRepository(mockConverter) 1229 1230 // WHEN 1231 err := repo.DeleteByExternalTenant(ctx, testExternal) 1232 1233 // THEN 1234 require.Error(t, err) 1235 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 1236 dbMock.AssertExpectations(t) 1237 mockConverter.AssertExpectations(t) 1238 }) 1239 1240 t.Run("Error when delete fails", func(t *testing.T) { 1241 // GIVEN 1242 tenantMappingModel := newModelBusinessTenantMapping(testID, testName) 1243 tenantMappingEntity := newEntityBusinessTenantMapping(testID, testName) 1244 1245 mockConverter := &automock.Converter{} 1246 mockConverter.On("FromEntity", tenantMappingEntity).Return(tenantMappingModel).Once() 1247 1248 db, dbMock := testdb.MockDatabase(t) 1249 rowsToReturn := fixSQLRows([]sqlRow{ 1250 {id: testID, name: testName, externalTenant: testExternal, parent: sql.NullString{}, typeRow: string(tenantEntity.Account), provider: "Compass", status: tenantEntity.Active}, 1251 }) 1252 dbMock.ExpectQuery(regexp.QuoteMeta(`SELECT id, external_name, external_tenant, parent, type, provider_name, status FROM public.business_tenant_mappings WHERE external_tenant = $1 AND status != $2 `)). 1253 WithArgs(testExternal, tenantEntity.Inactive). 1254 WillReturnRows(rowsToReturn) 1255 1256 for topLvlEntity := range resource.TopLevelEntities { 1257 if _, ok := topLvlEntity.IgnoredTenantAccessTable(); ok { 1258 continue 1259 } 1260 tenantAccesses := fixTenantAccesses() 1261 1262 dbMock.ExpectQuery(`SELECT tenant_id, id, owner FROM (.+) WHERE tenant_id = \$1 AND owner = \$2`). 1263 WithArgs(testID, true).WillReturnRows(sqlmock.NewRows(repo.M2MColumns).AddRow(fixTenantAccessesRow()...)) 1264 1265 dbMock.ExpectExec(`DELETE FROM (.+) WHERE id IN \(\$1\)`). 1266 WithArgs(tenantAccesses[0].ResourceID).WillReturnResult(sqlmock.NewResult(-1, 1)) 1267 } 1268 1269 dbMock.ExpectExec(deleteStatement). 1270 WithArgs(testExternal).WillReturnError(testError) 1271 1272 ctx := persistence.SaveToContext(context.TODO(), db) 1273 repo := tenant.NewRepository(mockConverter) 1274 1275 // WHEN 1276 err := repo.DeleteByExternalTenant(ctx, testExternal) 1277 1278 // THEN 1279 require.Error(t, err) 1280 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 1281 dbMock.AssertExpectations(t) 1282 mockConverter.AssertExpectations(t) 1283 }) 1284 } 1285 1286 func TestPgRepository_GetLowestOwnerForResource(t *testing.T) { 1287 runtimeID := "runtimeID" 1288 1289 t.Run("Success", func(t *testing.T) { 1290 db, dbMock := mockDBSuccess(t, runtimeID) 1291 defer dbMock.AssertExpectations(t) 1292 1293 ctx := persistence.SaveToContext(context.TODO(), db) 1294 tenantMappingRepo := tenant.NewRepository(nil) 1295 1296 // WHEN 1297 result, err := tenantMappingRepo.GetLowestOwnerForResource(ctx, resource.Runtime, runtimeID) 1298 1299 // THEN 1300 require.NoError(t, err) 1301 require.Equal(t, testID, result) 1302 }) 1303 1304 t.Run("Error when getting", func(t *testing.T) { 1305 db, dbMock := mockDBError(t, runtimeID) 1306 defer dbMock.AssertExpectations(t) 1307 1308 ctx := persistence.SaveToContext(context.TODO(), db) 1309 tenantMappingRepo := tenant.NewRepository(nil) 1310 1311 // WHEN 1312 result, err := tenantMappingRepo.GetLowestOwnerForResource(ctx, resource.Runtime, runtimeID) 1313 1314 // THEN 1315 require.Error(t, err) 1316 require.Empty(t, result) 1317 }) 1318 } 1319 1320 func TestPgRepository_GetCustomerIDParentRecursively(t *testing.T) { 1321 dbQuery := `WITH RECURSIVE parents AS 1322 (SELECT t1.id, t1.parent, t1.external_tenant, t1.type 1323 FROM business_tenant_mappings t1 1324 WHERE id = $1 1325 UNION ALL 1326 SELECT t2.id, t2.parent, t2.external_tenant, t2.type 1327 FROM business_tenant_mappings t2 1328 INNER JOIN parents p on p.parent = t2.id) 1329 SELECT external_tenant, type FROM parents WHERE parent is null` 1330 1331 t.Run("Success when parent and type are returned", func(t *testing.T) { 1332 // GIVEN 1333 db, dbMock := testdb.MockDatabase(t) 1334 1335 rowsToReturn := sqlmock.NewRows([]string{"external_tenant", "type"}).AddRow(testParentID, tenantEntity.TypeToStr(tenantEntity.Customer)) 1336 dbMock.ExpectQuery(regexp.QuoteMeta(dbQuery)). 1337 WithArgs(testID). 1338 WillReturnRows(rowsToReturn) 1339 1340 ctx := persistence.SaveToContext(context.TODO(), db) 1341 tenantMappingRepo := tenant.NewRepository(nil) 1342 1343 // WHEN 1344 customerID, err := tenantMappingRepo.GetCustomerIDParentRecursively(ctx, testID) 1345 1346 // THEN 1347 require.NoError(t, err) 1348 require.Equal(t, customerID, testParentID) 1349 dbMock.AssertExpectations(t) 1350 }) 1351 1352 t.Run("Error when executing db query", func(t *testing.T) { 1353 // GIVEN 1354 db, dbMock := testdb.MockDatabase(t) 1355 dbMock.ExpectQuery(regexp.QuoteMeta(dbQuery)). 1356 WithArgs(testID).WillReturnError(testError) 1357 1358 ctx := persistence.SaveToContext(context.TODO(), db) 1359 tenantMappingRepo := tenant.NewRepository(nil) 1360 1361 // WHEN 1362 customerID, err := tenantMappingRepo.GetCustomerIDParentRecursively(ctx, testID) 1363 1364 // THEN 1365 require.Error(t, err) 1366 require.Contains(t, err.Error(), "Internal Server Error: Unexpected error while executing SQL query") 1367 require.Empty(t, customerID) 1368 dbMock.AssertExpectations(t) 1369 }) 1370 1371 t.Run("Error if missing persistence context", func(t *testing.T) { 1372 // GIVEN 1373 ctx := context.TODO() 1374 tenantMappingRepo := tenant.NewRepository(nil) 1375 // WHEN 1376 _, err := tenantMappingRepo.GetCustomerIDParentRecursively(ctx, testID) 1377 // THEN 1378 require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error()) 1379 }) 1380 1381 t.Run("Return empty string when returned type is not customer", func(t *testing.T) { 1382 // GIVEN 1383 db, dbMock := testdb.MockDatabase(t) 1384 1385 rowsToReturn := sqlmock.NewRows([]string{"external_tenant", "type"}).AddRow(testParentID, tenantEntity.TypeToStr(tenantEntity.Account)) 1386 dbMock.ExpectQuery(regexp.QuoteMeta(dbQuery)). 1387 WithArgs(testID). 1388 WillReturnRows(rowsToReturn) 1389 1390 ctx := persistence.SaveToContext(context.TODO(), db) 1391 tenantMappingRepo := tenant.NewRepository(nil) 1392 1393 // WHEN 1394 customerID, err := tenantMappingRepo.GetCustomerIDParentRecursively(ctx, testID) 1395 1396 // THEN 1397 require.NoError(t, err) 1398 require.Empty(t, customerID) 1399 dbMock.AssertExpectations(t) 1400 }) 1401 1402 t.Run("Error when empty parent is returned", func(t *testing.T) { 1403 // GIVEN 1404 db, dbMock := testdb.MockDatabase(t) 1405 1406 rowsToReturn := sqlmock.NewRows([]string{"external_tenant", "type"}).AddRow("", tenantEntity.TypeToStr(tenantEntity.Customer)) 1407 dbMock.ExpectQuery(regexp.QuoteMeta(dbQuery)). 1408 WithArgs(testID). 1409 WillReturnRows(rowsToReturn) 1410 1411 ctx := persistence.SaveToContext(context.TODO(), db) 1412 tenantMappingRepo := tenant.NewRepository(nil) 1413 1414 // WHEN 1415 customerID, err := tenantMappingRepo.GetCustomerIDParentRecursively(ctx, testID) 1416 1417 // THEN 1418 expectedError := fmt.Sprintf("external parent customer ID for internal tenant ID: %s can not be empty", testID) 1419 require.Error(t, err) 1420 require.EqualError(t, err, expectedError) 1421 require.Empty(t, customerID) 1422 dbMock.AssertExpectations(t) 1423 }) 1424 } 1425 1426 const selectTenantsQuery = `(SELECT tenant_id FROM tenant_runtimes ta WHERE ta.id = $1 AND ta.owner = true AND (NOT EXISTS(SELECT 1 FROM public.business_tenant_mappings WHERE parent = ta.tenant_id) OR (NOT EXISTS(SELECT 1 FROM tenant_runtimes ta2 WHERE ta2.id = $2 AND ta2.owner = true AND ta2.tenant_id IN (SELECT id FROM public.business_tenant_mappings WHERE parent = ta.tenant_id)))))` 1427 1428 func mockDBSuccess(t *testing.T, runtimeID string) (*sqlx.DB, testdb.DBMock) { 1429 db, dbMock := testdb.MockDatabase(t) 1430 rowsToReturn := sqlmock.NewRows([]string{"tenant_id"}).AddRow(testID) 1431 dbMock.ExpectQuery(regexp.QuoteMeta(selectTenantsQuery)). 1432 WithArgs(runtimeID, runtimeID). 1433 WillReturnRows(rowsToReturn) 1434 return db, dbMock 1435 } 1436 1437 func mockDBError(t *testing.T, runtimeID string) (*sqlx.DB, testdb.DBMock) { 1438 db, dbMock := testdb.MockDatabase(t) 1439 dbMock.ExpectQuery(regexp.QuoteMeta(selectTenantsQuery)). 1440 WithArgs(runtimeID, runtimeID).WillReturnError(testError) 1441 return db, dbMock 1442 } 1443 1444 func id() string { 1445 return uuid.New().String() 1446 }