forked from baron/baron-sso
worksmobile 연동 & ory stack 26.2.0으로 업그레이드
This commit is contained in:
387
backend/internal/service/worksmobile_sync_service_test.go
Normal file
387
backend/internal/service/worksmobile_sync_service_test.go
Normal file
@@ -0,0 +1,387 @@
|
||||
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 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.Equal(t, "externalKey:"+companyID, request.ParentOrgUnitID)
|
||||
}
|
||||
|
||||
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, companyCode 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
|
||||
}
|
||||
Reference in New Issue
Block a user