1
0
forked from baron/baron-sso

네이버 웍스 연동기능 개선

This commit is contained in:
2026-05-18 15:36:30 +09:00
parent c71ece84b8
commit e29d056b9e
61 changed files with 4137 additions and 710 deletions

View File

@@ -166,10 +166,10 @@ func TestCompareWorksmobileGroupsUsesOrganizationsAndBarongroupChildCompanies(t
[]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-hanmac", ExternalID: hanmac.ID, DisplayName: hanmac.Name, Email: "hanmac@hanmaceng.co.kr"},
{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-organization", ExternalID: organization.ID, DisplayName: organization.Name, ParentID: "works-hanmac"},
{ID: "works-legacy-user-group", ExternalID: legacyUserGroup.ID, DisplayName: legacyUserGroup.Name},
{ID: "works-orphan", ExternalID: "works-orphan", DisplayName: "WORKS 전용 조직"},
},
@@ -181,6 +181,13 @@ func TestCompareWorksmobileGroupsUsesOrganizationsAndBarongroupChildCompanies(t
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-hanmac", items[1].WorksmobileParentID)
require.Equal(t, hanmac.Name, items[1].WorksmobileParentName)
require.Equal(t, "hanmac@hanmaceng.co.kr", items[1].WorksmobileParentEmail)
require.Equal(t, hanmac.ID, items[1].WorksmobileParentExternalKey)
require.Equal(t, "works-hanmac", items[1].BaronParentWorksmobileID)
require.Equal(t, hanmac.Name, items[1].BaronParentWorksmobileName)
require.Equal(t, "hanmac@hanmaceng.co.kr", items[1].BaronParentWorksmobileEmail)
require.Equal(t, "works-orphan", items[2].ExternalKey)
require.Equal(t, "missing_in_baron", items[2].Status)
}
@@ -304,6 +311,381 @@ func TestWorksmobileSyncServiceEnqueuesOrganizationOrgUnitSync(t *testing.T) {
request := outboxRepo.created[0].Payload["request"].(WorksmobileOrgUnitPayload)
require.Equal(t, organizationID, request.OrgUnitExternalKey)
require.Empty(t, request.ParentOrgUnitID)
require.Equal(t, 1, request.DisplayOrder)
}
func TestWorksmobileSyncServiceEnqueuesExternalKeyMissingOrgUnitDelete(t *testing.T) {
rootID := "root-tenant"
root := domain.Tenant{
ID: rootID,
Slug: HanmacFamilyTenantSlug,
Name: "한맥가족",
}
outboxRepo := &fakeWorksmobileOutboxRepo{}
client := &fakeWorksmobileDirectoryClient{
groups: []WorksmobileRemoteGroup{
{
ID: "works-org-1",
DisplayName: "WORKS 전용 조직",
DomainID: 1001,
ParentID: "works-parent",
},
},
}
service := NewWorksmobileSyncService(
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root}},
&fakeWorksmobileUserRepo{},
outboxRepo,
client,
)
item, err := service.EnqueueOrgUnitDelete(context.Background(), rootID, "works-org-1")
require.NoError(t, err)
require.NotNil(t, item)
require.Len(t, outboxRepo.created, 1)
require.Equal(t, domain.WorksmobileActionDelete, outboxRepo.created[0].Action)
require.Equal(t, "works-org-1", outboxRepo.created[0].Payload["worksmobileId"])
}
func TestWorksmobileSyncServiceEnqueuesExternalKeyPresentWorksOnlyOrgUnitDelete(t *testing.T) {
rootID := "root-tenant"
root := domain.Tenant{
ID: rootID,
Slug: HanmacFamilyTenantSlug,
Name: "한맥가족",
}
outboxRepo := &fakeWorksmobileOutboxRepo{}
client := &fakeWorksmobileDirectoryClient{
groups: []WorksmobileRemoteGroup{
{
ID: "works-org-1",
ExternalID: "baron-tenant-1",
ParentID: "works-parent",
},
},
}
service := NewWorksmobileSyncService(
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root}},
&fakeWorksmobileUserRepo{},
outboxRepo,
client,
)
item, err := service.EnqueueOrgUnitDelete(context.Background(), rootID, "works-org-1")
require.NoError(t, err)
require.NotNil(t, item)
require.Len(t, outboxRepo.created, 1)
require.Equal(t, domain.WorksmobileActionDelete, outboxRepo.created[0].Action)
require.Equal(t, "baron-tenant-1", outboxRepo.created[0].Payload["externalKey"])
}
func TestWorksmobileSyncServiceReconcilesWorksOnlyOrgUnitBySlugLocalPart(t *testing.T) {
t.Setenv("GPDTDC_DOMAIN_ID", "1001")
rootID := "root-tenant"
orgID := "baron-org-1"
root := domain.Tenant{
ID: rootID,
Slug: HanmacFamilyTenantSlug,
Name: "한맥가족",
}
organization := domain.Tenant{
ID: orgID,
Slug: "tech-dev-center",
Name: "기술개발센터",
Type: domain.TenantTypeOrganization,
ParentID: &rootID,
}
outboxRepo := &fakeWorksmobileOutboxRepo{}
client := &fakeWorksmobileDirectoryClient{
groups: []WorksmobileRemoteGroup{
{
ID: "works-org-1",
ExternalID: "legacy-external-key",
DisplayName: "기술개발센터",
MailLocalPart: "tech-dev-center",
DomainID: 1001,
ParentID: "works-parent",
},
},
}
service := NewWorksmobileSyncService(
&fakeWorksmobileTenantService{
tenants: map[string]domain.Tenant{rootID: root, orgID: organization},
list: []domain.Tenant{root, organization},
},
&fakeWorksmobileUserRepo{},
outboxRepo,
client,
)
item, err := service.EnqueueOrgUnitDelete(context.Background(), rootID, "works-org-1")
require.NoError(t, err)
require.NotNil(t, item)
require.Len(t, outboxRepo.created, 1)
require.Equal(t, domain.WorksmobileActionUpsert, outboxRepo.created[0].Action)
require.Equal(t, orgID, outboxRepo.created[0].ResourceID)
request := outboxRepo.created[0].Payload["request"].(WorksmobileOrgUnitPayload)
require.Equal(t, orgID, request.OrgUnitExternalKey)
require.Equal(t, "tech-dev-center", outboxRepo.created[0].Payload["matchLocalPart"])
}
func TestCompareWorksmobileGroupsFillsParentDisplayFromBaronParentMatch(t *testing.T) {
rootID := "root-tenant"
parent := domain.Tenant{
ID: "parent-tenant",
Name: "삼안",
Slug: "saman",
Type: domain.TenantTypeCompany,
ParentID: &rootID,
}
child := domain.Tenant{
ID: "child-tenant",
Name: "업무",
Slug: "operations",
Type: domain.TenantTypeOrganization,
ParentID: &parent.ID,
}
items := compareWorksmobileGroups(
[]domain.Tenant{
{ID: rootID, Name: "한맥가족", Slug: HanmacFamilyTenantSlug, Type: domain.TenantTypeCompanyGroup},
parent,
child,
},
[]WorksmobileRemoteGroup{
{ID: "works-parent", ExternalID: parent.ID, DisplayName: "삼안", Email: "saman@samaneng.com"},
{ID: "works-child", ExternalID: child.ID, DisplayName: "업무", ParentID: "works-parent"},
},
true,
)
require.Len(t, items, 1)
require.Equal(t, child.ID, items[0].BaronID)
require.Equal(t, "works-parent", items[0].WorksmobileParentID)
require.Equal(t, "삼안", items[0].WorksmobileParentName)
require.Equal(t, "saman@samaneng.com", items[0].WorksmobileParentEmail)
require.Equal(t, parent.ID, items[0].WorksmobileParentExternalKey)
}
func TestWorksmobileSyncServiceReconcilesTopLevelWorksOnlyOrgUnitBeforeProtectedDeleteGuard(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "1001")
rootID := "root-tenant"
orgID := "baron-operations"
root := domain.Tenant{
ID: rootID,
Slug: HanmacFamilyTenantSlug,
Name: "한맥가족",
}
samanID := "saman-tenant"
saman := domain.Tenant{
ID: samanID,
Slug: "saman",
Name: "삼안",
Type: domain.TenantTypeCompany,
ParentID: &rootID,
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
}
organization := domain.Tenant{
ID: orgID,
Slug: "operations",
Name: "업무",
Type: domain.TenantTypeOrganization,
ParentID: &samanID,
}
outboxRepo := &fakeWorksmobileOutboxRepo{}
client := &fakeWorksmobileDirectoryClient{
groups: []WorksmobileRemoteGroup{
{
ID: "works-operations",
ExternalID: "legacy-operations-id",
DisplayName: "업무팀",
Email: "operations@samaneng.com",
MailLocalPart: "operations",
DomainID: 1001,
},
},
}
service := NewWorksmobileSyncService(
&fakeWorksmobileTenantService{
tenants: map[string]domain.Tenant{rootID: root, samanID: saman, orgID: organization},
list: []domain.Tenant{root, saman, organization},
},
&fakeWorksmobileUserRepo{},
outboxRepo,
client,
)
item, err := service.EnqueueOrgUnitDelete(context.Background(), rootID, "works-operations")
require.NoError(t, err)
require.NotNil(t, item)
require.Len(t, outboxRepo.created, 1)
require.Equal(t, domain.WorksmobileActionUpsert, outboxRepo.created[0].Action)
require.Equal(t, orgID, outboxRepo.created[0].ResourceID)
request := outboxRepo.created[0].Payload["request"].(WorksmobileOrgUnitPayload)
require.Equal(t, orgID, request.OrgUnitExternalKey)
require.Equal(t, "operations", outboxRepo.created[0].Payload["matchLocalPart"])
}
func TestWorksmobileSyncServiceRejectsProtectedDomainRootOrgUnitDelete(t *testing.T) {
rootID := "root-tenant"
root := domain.Tenant{
ID: rootID,
Slug: HanmacFamilyTenantSlug,
Name: "한맥가족",
}
outboxRepo := &fakeWorksmobileOutboxRepo{}
client := &fakeWorksmobileDirectoryClient{
groups: []WorksmobileRemoteGroup{
{
ID: "works-root",
DisplayName: "한맥기술",
},
},
}
service := NewWorksmobileSyncService(
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root}, list: []domain.Tenant{root}},
&fakeWorksmobileUserRepo{},
outboxRepo,
client,
)
item, err := service.EnqueueOrgUnitDelete(context.Background(), rootID, "works-root")
require.Nil(t, item)
require.Error(t, err)
require.Contains(t, err.Error(), "protected worksmobile domain root")
require.Empty(t, outboxRepo.created)
}
func TestWorksmobileSyncServiceTreatsHanmacFamilyChildCompaniesAsDomainRoots(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "1001")
t.Setenv("HANMAC_DOMAIN_ID", "1002")
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
rootID := "root-tenant"
root := domain.Tenant{
ID: rootID,
Slug: HanmacFamilyTenantSlug,
Name: "한맥가족",
}
tests := []struct {
name string
company domain.Tenant
organization domain.Tenant
wantDomainID int64
wantEmail string
}{
{
name: "saman",
company: domain.Tenant{
ID: "company-saman",
Slug: "saman",
Name: "삼안",
Type: domain.TenantTypeCompany,
ParentID: &rootID,
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
},
organization: domain.Tenant{
ID: "org-saman-planning",
Slug: "saman-planning",
Name: "삼안 기획팀",
Type: domain.TenantTypeOrganization,
},
wantDomainID: 1001,
wantEmail: "saman-planning@samaneng.com",
},
{
name: "hanmac",
company: domain.Tenant{
ID: "company-hanmac",
Slug: "hanmac",
Name: "한맥기술",
Type: domain.TenantTypeCompany,
ParentID: &rootID,
Domains: []domain.TenantDomain{{Domain: "hanmaceng.co.kr"}},
},
organization: domain.Tenant{
ID: "org-hanmac-planning",
Slug: "hanmac-planning",
Name: "한맥 기획팀",
Type: domain.TenantTypeOrganization,
},
wantDomainID: 1002,
wantEmail: "hanmac-planning@hanmaceng.co.kr",
},
{
name: "gpdtdc",
company: domain.Tenant{
ID: "company-gpdtdc",
Slug: "gpdtdc",
Name: "총괄기획&기술개발센터",
Type: domain.TenantTypeCompany,
ParentID: &rootID,
},
organization: domain.Tenant{
ID: "org-gpdtdc-planning",
Slug: "gpdtdc-planning",
Name: "총괄 기획팀",
Type: domain.TenantTypeOrganization,
},
wantDomainID: 1003,
wantEmail: "gpdtdc-planning@baroncs.co.kr",
},
{
name: "baron-group",
company: domain.Tenant{
ID: "company-barongroup",
Slug: "baron-group",
Name: "바론그룹",
Type: domain.TenantTypeCompany,
ParentID: &rootID,
},
organization: domain.Tenant{
ID: "org-baron-planning",
Slug: "baron-planning",
Name: "바론 기획팀",
Type: domain.TenantTypeOrganization,
},
wantDomainID: 1004,
wantEmail: "baron-planning@brsw.kr",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
organization := tt.organization
organization.ParentID = &tt.company.ID
outboxRepo := &fakeWorksmobileOutboxRepo{}
service := NewWorksmobileSyncService(
&fakeWorksmobileTenantService{
tenants: map[string]domain.Tenant{
rootID: root,
tt.company.ID: tt.company,
organization.ID: organization,
},
list: []domain.Tenant{root, tt.company, organization},
},
&fakeWorksmobileUserRepo{},
outboxRepo,
nil,
)
item, err := service.EnqueueOrgUnitSync(context.Background(), rootID, organization.ID)
require.NoError(t, err)
require.NotNil(t, item)
require.Len(t, outboxRepo.created, 1)
request := outboxRepo.created[0].Payload["request"].(WorksmobileOrgUnitPayload)
require.Equal(t, organization.ID, request.OrgUnitExternalKey)
require.Equal(t, tt.wantDomainID, request.DomainID)
require.Equal(t, tt.wantEmail, request.Email)
require.Empty(t, request.ParentOrgUnitID)
})
}
}
func TestWorksmobileDomainClassificationUsesAncestorCompanyForGPDTDCOrganization(t *testing.T) {