forked from baron/baron-sso
456 lines
15 KiB
Go
456 lines
15 KiB
Go
package service
|
|
|
|
import (
|
|
"baron-sso-backend/internal/domain"
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestWorksmobileSyncServiceRejectsAliasLocalPartAlreadyUsedByOtherUser(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
tenantID := "saman-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
tenant := domain.Tenant{
|
|
ID: tenantID,
|
|
Slug: "saman",
|
|
Name: "삼안",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
target := domain.User{
|
|
ID: "target-user",
|
|
Email: "target@samaneng.com",
|
|
Name: "Target",
|
|
TenantID: &tenantID,
|
|
Metadata: domain.JSONMap{
|
|
"aliasEmails": []any{"used@hanmaceng.co.kr"},
|
|
},
|
|
}
|
|
existing := domain.User{
|
|
ID: "existing-user",
|
|
Email: "used@samaneng.com",
|
|
Name: "Existing",
|
|
TenantID: &tenantID,
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root, tenantID: tenant}, list: []domain.Tenant{root, tenant}},
|
|
&fakeWorksmobileUserRepo{byID: map[string]domain.User{target.ID: target}, byTenant: []domain.User{target, existing}},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueUserSync(context.Background(), rootID, target.ID)
|
|
|
|
require.Nil(t, item)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "이미 사용 중")
|
|
require.Empty(t, outboxRepo.created)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceOverviewExposesAdminTenantIDForPasswordManageLink(t *testing.T) {
|
|
t.Setenv("WORKS_ADMIN_TENANT_ID", "works-tenant-1")
|
|
root := domain.Tenant{
|
|
ID: "root-tenant",
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{root.ID: root}},
|
|
&fakeWorksmobileUserRepo{},
|
|
&fakeWorksmobileOutboxRepo{},
|
|
nil,
|
|
)
|
|
|
|
overview, err := service.GetTenantOverview(context.Background(), root.ID)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, "works-tenant-1", overview.Config.AdminTenantID)
|
|
}
|
|
|
|
func TestCompareWorksmobileGroupsUsesOrganizationsAndBarongroupChildCompanies(t *testing.T) {
|
|
parentID := "root-tenant"
|
|
root := domain.Tenant{
|
|
ID: parentID,
|
|
Name: "한맥가족",
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Type: domain.TenantTypeCompanyGroup,
|
|
}
|
|
hanmac := domain.Tenant{
|
|
ID: "hanmac-tenant",
|
|
Name: "한맥기술",
|
|
Slug: "hanmac",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &parentID,
|
|
}
|
|
barongroup := domain.Tenant{
|
|
ID: "barongroup-tenant",
|
|
Name: "바론그룹",
|
|
Slug: "baron-group",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &parentID,
|
|
}
|
|
barongroupChildCompany := domain.Tenant{
|
|
ID: "barongroup-child-company",
|
|
Name: "바론그룹 하위 회사",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &barongroup.ID,
|
|
}
|
|
organization := domain.Tenant{
|
|
ID: "organization-tenant",
|
|
Name: "정규 조직",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &hanmac.ID,
|
|
}
|
|
legacyUserGroup := domain.Tenant{
|
|
ID: "legacy-user-group-tenant",
|
|
Name: "레거시 사용자 그룹",
|
|
Type: domain.TenantTypeUserGroup,
|
|
ParentID: &hanmac.ID,
|
|
}
|
|
|
|
items := compareWorksmobileGroups(
|
|
[]domain.Tenant{root, hanmac, barongroup, barongroupChildCompany, organization, legacyUserGroup},
|
|
[]WorksmobileRemoteGroup{
|
|
{ID: "works-root", ExternalID: root.ID, DisplayName: root.Name},
|
|
{ID: "works-hanmac", ExternalID: hanmac.ID, DisplayName: hanmac.Name},
|
|
{ID: "works-barongroup", ExternalID: barongroup.ID, DisplayName: barongroup.Name},
|
|
{ID: "works-barongroup-child", ExternalID: barongroupChildCompany.ID, DisplayName: barongroupChildCompany.Name},
|
|
{ID: "works-organization", ExternalID: organization.ID, DisplayName: organization.Name},
|
|
{ID: "works-legacy-user-group", ExternalID: legacyUserGroup.ID, DisplayName: legacyUserGroup.Name},
|
|
{ID: "works-orphan", ExternalID: "works-orphan", DisplayName: "WORKS 전용 조직"},
|
|
},
|
|
true,
|
|
)
|
|
|
|
require.Len(t, items, 3)
|
|
require.Equal(t, barongroupChildCompany.ID, items[0].BaronID)
|
|
require.Equal(t, "matched", items[0].Status)
|
|
require.Equal(t, organization.ID, items[1].BaronID)
|
|
require.Equal(t, "matched", items[1].Status)
|
|
require.Equal(t, "works-orphan", items[2].ExternalKey)
|
|
require.Equal(t, "missing_in_baron", items[2].Status)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceRejectsDomainCompanyOrgUnitSync(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
companyID := "company-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Slug: "saman",
|
|
Name: "삼안",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root, companyID: company}, list: []domain.Tenant{root, company}},
|
|
&fakeWorksmobileUserRepo{},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueOrgUnitSync(context.Background(), rootID, companyID)
|
|
|
|
require.Nil(t, item)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "worksmobile orgunit tenant")
|
|
require.Empty(t, outboxRepo.created)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceEnqueuesBarongroupChildCompanyOrgUnitSync(t *testing.T) {
|
|
t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
|
|
rootID := "root-tenant"
|
|
barongroupID := "barongroup-tenant"
|
|
companyID := "barongroup-child-company"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
barongroup := domain.Tenant{
|
|
ID: barongroupID,
|
|
Slug: "baron-group",
|
|
Name: "바론그룹",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Slug: "barongroup-child",
|
|
Name: "바론그룹 하위 회사",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &barongroupID,
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root, barongroupID: barongroup, companyID: company}, list: []domain.Tenant{root, barongroup, company}},
|
|
&fakeWorksmobileUserRepo{},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueOrgUnitSync(context.Background(), rootID, companyID)
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, item)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
request := outboxRepo.created[0].Payload["request"].(WorksmobileOrgUnitPayload)
|
|
require.Equal(t, companyID, request.OrgUnitExternalKey)
|
|
require.Empty(t, request.ParentOrgUnitID)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceEnqueuesOrganizationOrgUnitSync(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
companyID := "company-tenant"
|
|
organizationID := "organization-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Slug: "saman",
|
|
Name: "삼안",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
organization := domain.Tenant{
|
|
ID: organizationID,
|
|
Slug: "engineering",
|
|
Name: "기술본부",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &companyID,
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{
|
|
tenants: map[string]domain.Tenant{rootID: root, companyID: company, organizationID: organization},
|
|
list: []domain.Tenant{root, company, organization},
|
|
},
|
|
&fakeWorksmobileUserRepo{},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueOrgUnitSync(context.Background(), rootID, organizationID)
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, item)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
request := outboxRepo.created[0].Payload["request"].(WorksmobileOrgUnitPayload)
|
|
require.Equal(t, organizationID, request.OrgUnitExternalKey)
|
|
require.Empty(t, request.ParentOrgUnitID)
|
|
}
|
|
|
|
func TestWorksmobileDomainClassificationUsesAncestorCompanyForGPDTDCOrganization(t *testing.T) {
|
|
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
|
|
rootID := "root-tenant"
|
|
companyID := "company-tenant"
|
|
organizationID := "organization-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Slug: "gpdtdc",
|
|
Name: "총괄기획&기술개발센터",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "baroncs.co.kr"}},
|
|
}
|
|
organization := domain.Tenant{
|
|
ID: organizationID,
|
|
Slug: "gpd",
|
|
Name: "총괄기획실",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &companyID,
|
|
}
|
|
tenantByID := worksmobileTenantByID([]domain.Tenant{root, company, organization})
|
|
|
|
domainTenant := worksmobileDomainClassificationTenant(organization, tenantByID)
|
|
payload, err := BuildWorksmobileOrgUnitPayloadForDomainTenant(organization, domainTenant, nil, 1)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, companyID, domainTenant.ID)
|
|
require.Equal(t, int64(1003), payload.DomainID)
|
|
require.Equal(t, "gpd@baroncs.co.kr", payload.Email)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceKeepsCompanyUsersInComparisonScope(t *testing.T) {
|
|
rootID := "root-tenant"
|
|
companyID := "company-tenant"
|
|
userGroupID := "user-group-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Name: "계열사",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
}
|
|
userGroup := domain.Tenant{
|
|
ID: userGroupID,
|
|
Name: "연동 조직",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &companyID,
|
|
}
|
|
userRepo := &fakeWorksmobileUserRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root, companyID: company, userGroupID: userGroup}, list: []domain.Tenant{root, company, userGroup}},
|
|
userRepo,
|
|
&fakeWorksmobileOutboxRepo{},
|
|
&fakeWorksmobileDirectoryClient{},
|
|
)
|
|
|
|
_, err := service.GetComparison(context.Background(), rootID, true)
|
|
|
|
require.NoError(t, err)
|
|
require.ElementsMatch(t, []string{companyID, userGroupID}, userRepo.requestedTenantIDs)
|
|
}
|
|
|
|
type fakeWorksmobileTenantService struct {
|
|
tenants map[string]domain.Tenant
|
|
list []domain.Tenant
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) RegisterTenant(ctx context.Context, name, slug, tenantType, description string, domains []string, parentID *string, creatorID string) (*domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) RequestRegistration(ctx context.Context, name, slug, description string, domainName string, adminEmail string) (*domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) GetTenantByDomain(ctx context.Context, emailDomain string) (*domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) GetTenantBySlug(ctx context.Context, slug string) (*domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) GetTenant(ctx context.Context, id string) (*domain.Tenant, error) {
|
|
tenant := f.tenants[id]
|
|
return &tenant, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) ListTenants(ctx context.Context, limit, offset int, parentID string) ([]domain.Tenant, int64, error) {
|
|
return f.list, int64(len(f.list)), nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) ListManageableTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) ListJoinedTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) IsDomainAllowed(ctx context.Context, domainName string) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) ApproveTenant(ctx context.Context, id string) error {
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) ProvisionTenantByDomain(ctx context.Context, domainName string) (*domain.Tenant, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileTenantService) SetKetoService(keto KetoService) {}
|
|
|
|
func (f *fakeWorksmobileTenantService) DeleteTenantsBulk(ctx context.Context, ids []string) error {
|
|
return nil
|
|
}
|
|
|
|
type fakeWorksmobileUserRepo struct {
|
|
byID map[string]domain.User
|
|
byTenant []domain.User
|
|
requestedTenantIDs []string
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) Create(ctx context.Context, user *domain.User) error { return nil }
|
|
func (f *fakeWorksmobileUserRepo) Update(ctx context.Context, user *domain.User) error { return nil }
|
|
func (f *fakeWorksmobileUserRepo) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) FindByID(ctx context.Context, id string) (*domain.User, error) {
|
|
user := f.byID[id]
|
|
return &user, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) FindByIDs(ctx context.Context, ids []string) ([]domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) ListByTenant(ctx context.Context, tenantID string) ([]domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) List(ctx context.Context, offset, limit int, search string, tenantSlug string) ([]domain.User, int64, error) {
|
|
return nil, 0, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) CountByTenant(ctx context.Context, tenantID string) (int64, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) CountByTenantIDs(ctx context.Context, tenantIDs []string) (map[string]int64, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) CountByCompanyCodes(ctx context.Context, codes []string) (map[string]int64, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) FindByTenantIDs(ctx context.Context, tenantIDs []string) ([]domain.User, error) {
|
|
f.requestedTenantIDs = append([]string(nil), tenantIDs...)
|
|
return f.byTenant, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) FindByCompanyCodes(ctx context.Context, codes []string) ([]domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
func (f *fakeWorksmobileUserRepo) Delete(ctx context.Context, id string) error { return nil }
|
|
func (f *fakeWorksmobileUserRepo) UpdateUserLoginIDs(ctx context.Context, userID string, loginIDs []domain.UserLoginID) error {
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) GetUserLoginIDs(ctx context.Context, userID string) ([]domain.UserLoginID, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) IsLoginIDTaken(ctx context.Context, loginID string) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) FindTenantIDByLoginID(ctx context.Context, loginID string) (string, error) {
|
|
return "", nil
|
|
}
|