package repository import ( "baron-sso-backend/internal/domain" "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestTenantRepository(t *testing.T) { repo := NewTenantRepository(testDB) ctx := context.Background() t.Run("Create and FindByID", func(t *testing.T) { tenant := &domain.Tenant{ Name: "Test Tenant", Slug: "test-tenant", Type: domain.TenantTypeCompany, } err := repo.Create(ctx, tenant) assert.NoError(t, err) assert.NotEmpty(t, tenant.ID) found, err := repo.FindByID(ctx, tenant.ID) assert.NoError(t, err) assert.Equal(t, tenant.Name, found.Name) assert.Equal(t, tenant.Slug, found.Slug) }) t.Run("FindBySlug", func(t *testing.T) { tenant := &domain.Tenant{ Name: "Slug Test", Slug: "slug-test", Type: domain.TenantTypeCompany, } _ = repo.Create(ctx, tenant) found, err := repo.FindBySlug(ctx, "slug-test") assert.NoError(t, err) assert.Equal(t, tenant.ID, found.ID) }) t.Run("AddDomain and FindByDomain", func(t *testing.T) { tenant := &domain.Tenant{ Name: "Domain Test", Slug: "domain-test", Type: domain.TenantTypeCompany, } _ = repo.Create(ctx, tenant) err := repo.AddDomain(ctx, tenant.ID, "test-domain.com", true) assert.NoError(t, err) found, err := repo.FindByDomain(ctx, "test-domain.com") assert.NoError(t, err) assert.Equal(t, tenant.ID, found.ID) assert.Len(t, found.Domains, 1) assert.Equal(t, "test-domain.com", found.Domains[0].Domain) }) t.Run("AddDomain allows same domain on multiple tenants", func(t *testing.T) { first := &domain.Tenant{ Name: "Saman Existing", Slug: "saman-existing", Type: domain.TenantTypeCompany, } second := &domain.Tenant{ Name: "Saman Current", Slug: "saman-current", Type: domain.TenantTypeCompany, } assert.NoError(t, repo.Create(ctx, first)) assert.NoError(t, repo.Create(ctx, second)) assert.NoError(t, repo.AddDomain(ctx, first.ID, "samaneng.com", true)) assert.NoError(t, repo.AddDomain(ctx, second.ID, "samaneng.com", true)) var rows []domain.TenantDomain err := testDB.Where("domain = ?", "samaneng.com").Find(&rows).Error assert.NoError(t, err) assert.Len(t, rows, 2) }) t.Run("AddDomain restores deleted tenant domain", func(t *testing.T) { tenant := &domain.Tenant{ Name: "Domain Restore", Slug: "domain-restore", Type: domain.TenantTypeCompany, } assert.NoError(t, repo.Create(ctx, tenant)) assert.NoError(t, repo.AddDomain(ctx, tenant.ID, "restore.samaneng.com", true)) assert.NoError(t, testDB.Where("tenant_id = ? AND domain = ?", tenant.ID, "restore.samaneng.com").Delete(&domain.TenantDomain{}).Error) assert.NoError(t, repo.AddDomain(ctx, tenant.ID, "restore.samaneng.com", true)) var rows []domain.TenantDomain err := testDB.Where("tenant_id = ? AND domain = ?", tenant.ID, "restore.samaneng.com").Find(&rows).Error assert.NoError(t, err) if assert.Len(t, rows, 1) { assert.True(t, rows[0].Verified) } }) t.Run("Update", func(t *testing.T) { tenant := &domain.Tenant{ Name: "Before Update", Slug: "before-update", Type: domain.TenantTypeCompany, } _ = repo.Create(ctx, tenant) tenant.Name = "After Update" err := repo.Update(ctx, tenant) assert.NoError(t, err) found, err := repo.FindByID(ctx, tenant.ID) assert.NoError(t, err) assert.Equal(t, "After Update", found.Name) }) t.Run("Hierarchy", func(t *testing.T) { parent := &domain.Tenant{ Name: "Parent Tenant", Slug: "parent-hierarchy", Type: domain.TenantTypeCompanyGroup, } err := repo.Create(ctx, parent) assert.NoError(t, err) child := &domain.Tenant{ Name: "Child Tenant", Slug: "child-hierarchy", Type: domain.TenantTypeCompany, ParentID: &parent.ID, } err = repo.Create(ctx, child) assert.NoError(t, err) foundChild, err := repo.FindByID(ctx, child.ID) assert.NoError(t, err) assert.Equal(t, parent.ID, *foundChild.ParentID) }) t.Run("Unique Constraint on Slug", func(t *testing.T) { slug := "unique-slug-test" tenant1 := &domain.Tenant{ Name: "First", Slug: slug, Type: domain.TenantTypeCompany, } err := repo.Create(ctx, tenant1) assert.NoError(t, err) tenant2 := &domain.Tenant{ Name: "Second", Slug: slug, Type: domain.TenantTypeCompany, } err = repo.Create(ctx, tenant2) assert.Error(t, err) // Should fail due to UNIQUE constraint }) t.Run("Create reuses slug held by legacy soft-deleted tenant", func(t *testing.T) { slug := "legacy-soft-delete-reuse" require.NoError(t, testDB.Unscoped().Where("slug = ?", slug).Delete(&domain.Tenant{}).Error) legacy := &domain.Tenant{ Name: "Legacy Deleted", Slug: slug, Type: domain.TenantTypeCompany, } require.NoError(t, repo.Create(ctx, legacy)) require.NoError(t, testDB.Delete(&domain.Tenant{}, "id = ?", legacy.ID).Error) _, err := repo.FindBySlug(ctx, slug) require.Error(t, err) replacement := &domain.Tenant{ Name: "Replacement", Slug: slug, Type: domain.TenantTypeCompany, } require.NoError(t, repo.Create(ctx, replacement)) found, err := repo.FindBySlug(ctx, slug) require.NoError(t, err) assert.Equal(t, replacement.ID, found.ID) }) }