forked from baron/baron-sso
1780 lines
58 KiB
Go
1780 lines
58 KiB
Go
package service
|
|
|
|
import (
|
|
"baron-sso-backend/internal/domain"
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestWorksmobileSyncServiceRejectsAliasEmailAlreadyUsedByOtherUser(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@hanmaceng.co.kr",
|
|
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 TestWorksmobileSyncServiceEnqueuesSuspendedUserStatusWithOrganizations(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
tenantID := "saman-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "Hanmac Family",
|
|
}
|
|
tenant := domain.Tenant{
|
|
ID: tenantID,
|
|
Slug: "saman",
|
|
Name: "Saman",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
target := domain.User{
|
|
ID: "target-user",
|
|
Email: "target@samaneng.com",
|
|
Name: "Target",
|
|
Status: domain.UserStatusSuspended,
|
|
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}},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueUserSync(context.Background(), rootID, target.ID, "")
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, item)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
require.Equal(t, domain.WorksmobileActionSuspend, outboxRepo.created[0].Action)
|
|
require.Equal(t, domain.UserStatusSuspended, outboxRepo.created[0].Payload["baronStatus"])
|
|
request, ok := outboxRepo.created[0].Payload["request"].(WorksmobileUserPayload)
|
|
require.True(t, ok)
|
|
require.NotEmpty(t, request.Organizations)
|
|
require.Equal(t, "target@samaneng.com", outboxRepo.created[0].Payload["loginEmail"])
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceEnqueuesUserCredentialBatchID(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
tenantID := "saman-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "Hanmac Family",
|
|
}
|
|
tenant := domain.Tenant{
|
|
ID: tenantID,
|
|
Slug: "saman",
|
|
Name: "Saman",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
target := domain.User{
|
|
ID: "target-user",
|
|
Email: "target@samaneng.com",
|
|
Name: "Target",
|
|
Status: domain.UserStatusActive,
|
|
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}},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueUserSync(context.Background(), rootID, target.ID, "batch-1")
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, item)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
require.Equal(t, "batch-1", outboxRepo.created[0].Payload["credentialBatchId"])
|
|
require.NotEmpty(t, outboxRepo.created[0].Payload["credentialBatchCreatedAt"])
|
|
require.Equal(t, "Target", outboxRepo.created[0].Payload["displayName"])
|
|
require.Equal(t, "Saman", outboxRepo.created[0].Payload["primaryLeafOrgName"])
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceEnqueuesUserPasswordResetCredentialBatch(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
tenantID := "saman-leaf"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "Hanmac Family",
|
|
}
|
|
tenant := domain.Tenant{
|
|
ID: tenantID,
|
|
Slug: "people-growth",
|
|
Name: "인재성장",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
target := domain.User{
|
|
ID: "target-user",
|
|
Email: "target@samaneng.com",
|
|
Name: "Target",
|
|
Status: domain.UserStatusActive,
|
|
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}},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueUserPasswordReset(context.Background(), rootID, target.ID, "reset-batch-1")
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, item)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
require.Equal(t, domain.WorksmobileActionPasswordReset, outboxRepo.created[0].Action)
|
|
require.Equal(t, "reset-batch-1", outboxRepo.created[0].Payload["credentialBatchId"])
|
|
require.Equal(t, "worksmobile_password_reset", outboxRepo.created[0].Payload["credentialOperation"])
|
|
require.NotEmpty(t, outboxRepo.created[0].Payload["credentialBatchCreatedAt"])
|
|
require.Equal(t, "target@samaneng.com", outboxRepo.created[0].Payload["loginEmail"])
|
|
require.Equal(t, "Target", outboxRepo.created[0].Payload["displayName"])
|
|
require.Equal(t, "인재성장", outboxRepo.created[0].Payload["primaryLeafOrgName"])
|
|
require.NotEmpty(t, outboxRepo.created[0].Payload["initialPassword"])
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceFiltersInitialPasswordsByCredentialBatchID(t *testing.T) {
|
|
rootID := "root-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "Hanmac Family",
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{
|
|
credentialBatchJobs: []domain.WorksmobileOutbox{
|
|
{
|
|
ResourceType: domain.WorksmobileResourceUser,
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
Payload: domain.JSONMap{
|
|
"tenantRootId": rootID,
|
|
"loginEmail": "batch-user@samaneng.com",
|
|
"displayName": "Batch User",
|
|
"primaryLeafOrgName": "인재성장",
|
|
"initialPassword": "BatchPass1!",
|
|
"credentialBatchId": "batch-1",
|
|
},
|
|
},
|
|
{
|
|
ResourceType: domain.WorksmobileResourceUser,
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
Payload: domain.JSONMap{
|
|
"tenantRootId": rootID,
|
|
"loginEmail": "other-user@samaneng.com",
|
|
"initialPassword": "OtherPass1!",
|
|
"credentialBatchId": "batch-2",
|
|
},
|
|
},
|
|
{
|
|
ResourceType: domain.WorksmobileResourceUser,
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
Payload: domain.JSONMap{
|
|
"tenantRootId": rootID,
|
|
"loginEmail": "legacy-user@samaneng.com",
|
|
"initialPassword": "LegacyPass1!",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root}, list: []domain.Tenant{root}},
|
|
&fakeWorksmobileUserRepo{},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
credentials, err := service.ListInitialPasswordCredentials(context.Background(), rootID, "batch-1")
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, []WorksmobileInitialPasswordCredential{
|
|
{
|
|
Email: "batch-user@samaneng.com",
|
|
Name: "Batch User",
|
|
PrimaryLeafOrgName: "인재성장",
|
|
InitialPassword: "BatchPass1!",
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
},
|
|
}, credentials)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceDeletesCredentialBatchPasswordsButKeepsHistory(t *testing.T) {
|
|
rootID := "root-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "Hanmac Family",
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{
|
|
credentialBatchJobs: []domain.WorksmobileOutbox{
|
|
{
|
|
ID: "job-1",
|
|
ResourceType: domain.WorksmobileResourceUser,
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
Payload: domain.JSONMap{
|
|
"tenantRootId": rootID,
|
|
"loginEmail": "batch-user@samaneng.com",
|
|
"initialPassword": "BatchPass1!",
|
|
"credentialBatchId": "batch-1",
|
|
"credentialOperation": "worksmobile_user_sync",
|
|
"request": map[string]any{"passwordConfig": map[string]any{"password": "BatchPass1!"}},
|
|
},
|
|
},
|
|
{
|
|
ID: "job-2",
|
|
ResourceID: "failed-user",
|
|
ResourceType: domain.WorksmobileResourceUser,
|
|
Status: domain.WorksmobileOutboxStatusFailed,
|
|
RetryCount: 2,
|
|
LastError: "worksmobile api failed",
|
|
Payload: domain.JSONMap{
|
|
"tenantRootId": rootID,
|
|
"loginEmail": "failed-user@samaneng.com",
|
|
"initialPassword": "FailedPass1!",
|
|
"credentialBatchId": "batch-1",
|
|
"credentialOperation": "worksmobile_user_sync",
|
|
"request": map[string]any{"passwordConfig": map[string]any{"password": "FailedPass1!"}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root}, list: []domain.Tenant{root}},
|
|
&fakeWorksmobileUserRepo{},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
before, err := service.ListCredentialBatches(context.Background(), rootID)
|
|
require.NoError(t, err)
|
|
require.Len(t, before, 1)
|
|
require.True(t, before[0].HasPasswords)
|
|
require.Equal(t, 1, before[0].FailedCount)
|
|
require.Len(t, before[0].Failures, 1)
|
|
require.Equal(t, "failed-user", before[0].Failures[0].UserID)
|
|
require.Equal(t, "failed-user@samaneng.com", before[0].Failures[0].Email)
|
|
require.Equal(t, "worksmobile api failed", before[0].Failures[0].LastError)
|
|
|
|
after, err := service.DeleteCredentialBatchPasswords(context.Background(), rootID, "batch-1")
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, "batch-1", after.BatchID)
|
|
require.False(t, after.HasPasswords)
|
|
require.Equal(t, 2, after.UserCount)
|
|
require.NotEmpty(t, after.DeletedAt)
|
|
require.Len(t, outboxRepo.payloadUpdates, 2)
|
|
require.Empty(t, stringValue(outboxRepo.payloadUpdates[0]["initialPassword"]))
|
|
require.Empty(t, stringValue(outboxRepo.payloadUpdates[1]["initialPassword"]))
|
|
request := outboxRepo.payloadUpdates[0]["request"].(map[string]any)
|
|
passwordConfig := request["passwordConfig"].(map[string]any)
|
|
require.Empty(t, stringValue(passwordConfig["password"]))
|
|
}
|
|
|
|
func TestAggregateWorksmobileCredentialBatchesUsesCredentialBatchCreatedAt(t *testing.T) {
|
|
oldCreatedAt := time.Date(2026, 5, 29, 1, 4, 15, 0, time.UTC)
|
|
batchCreatedAt := time.Date(2026, 6, 1, 7, 20, 0, 0, time.UTC)
|
|
|
|
batches := aggregateWorksmobileCredentialBatches([]domain.WorksmobileOutbox{
|
|
{
|
|
ID: "job-1",
|
|
CreatedAt: oldCreatedAt,
|
|
UpdatedAt: batchCreatedAt.Add(time.Minute),
|
|
Status: domain.WorksmobileOutboxStatusPending,
|
|
Payload: domain.JSONMap{
|
|
"credentialBatchId": "batch-1",
|
|
"credentialOperation": "worksmobile_user_sync",
|
|
"credentialBatchCreatedAt": batchCreatedAt.Format(time.RFC3339),
|
|
},
|
|
},
|
|
})
|
|
|
|
require.Len(t, batches, 1)
|
|
require.Equal(t, batchCreatedAt, batches[0].CreatedAt)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceDeprovisionsArchivedUser(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
rootID := "root-tenant"
|
|
tenantID := "saman-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "Hanmac Family",
|
|
}
|
|
tenant := domain.Tenant{
|
|
ID: tenantID,
|
|
Slug: "saman",
|
|
Name: "Saman",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
|
|
}
|
|
target := domain.User{
|
|
ID: "archived-user",
|
|
Email: "archived@samaneng.com",
|
|
Name: "Archived",
|
|
Status: domain.UserStatusArchived,
|
|
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}},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
item, err := service.EnqueueUserSync(context.Background(), rootID, target.ID, "")
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, item)
|
|
require.Equal(t, domain.WorksmobileActionDelete, item.Action)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
|
|
err = service.EnqueueUserUpsertIfInScope(context.Background(), target)
|
|
require.NoError(t, err)
|
|
require.Len(t, outboxRepo.created, 2)
|
|
require.Equal(t, domain.WorksmobileActionDelete, outboxRepo.created[1].Action)
|
|
}
|
|
|
|
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 TestWorksmobileSyncServiceOverviewKeepsSafeRecentJobChangeLogPayload(t *testing.T) {
|
|
root := domain.Tenant{
|
|
ID: "root-tenant",
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{
|
|
recent: []domain.WorksmobileOutbox{
|
|
{
|
|
ID: "job-user-upsert",
|
|
ResourceType: domain.WorksmobileResourceUser,
|
|
ResourceID: "user-1",
|
|
Action: domain.WorksmobileActionUpsert,
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
Payload: domain.JSONMap{
|
|
"loginEmail": "changed@example.com",
|
|
"displayName": "변경 사용자",
|
|
"primaryLeafOrgName": "인재성장",
|
|
"initialPassword": "Secret123!",
|
|
"request": WorksmobileUserPayload{
|
|
Email: "changed@example.com",
|
|
UserExternalKey: "user-1",
|
|
UserName: WorksmobileUserName{LastName: "변경 사용자"},
|
|
PasswordConfig: WorksmobilePasswordConfig{Password: "Secret123!"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ID: "job-org-upsert",
|
|
ResourceType: domain.WorksmobileResourceOrgUnit,
|
|
ResourceID: "org-1",
|
|
Action: domain.WorksmobileActionUpsert,
|
|
Status: domain.WorksmobileOutboxStatusProcessed,
|
|
Payload: domain.JSONMap{
|
|
"matchLocalPart": "people-growth",
|
|
"request": WorksmobileOrgUnitPayload{
|
|
OrgUnitName: "인재성장",
|
|
Email: "people-growth@example.com",
|
|
OrgUnitExternalKey: "org-1",
|
|
ParentOrgUnitID: "externalKey:parent-1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{root.ID: root}},
|
|
&fakeWorksmobileUserRepo{},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
overview, err := service.GetTenantOverview(context.Background(), root.ID)
|
|
|
|
require.NoError(t, err)
|
|
require.Len(t, overview.RecentJobs, 2)
|
|
userPayload := overview.RecentJobs[0].Payload
|
|
require.Equal(t, "changed@example.com", userPayload["loginEmail"])
|
|
require.Equal(t, "변경 사용자", userPayload["displayName"])
|
|
require.Equal(t, "인재성장", userPayload["primaryLeafOrgName"])
|
|
require.NotContains(t, userPayload, "initialPassword")
|
|
require.NotContains(t, userPayload, "request")
|
|
require.Equal(t, domain.JSONMap{
|
|
"email": "changed@example.com",
|
|
"displayName": "변경 사용자",
|
|
"userExternalKey": "user-1",
|
|
}, userPayload["requestSummary"])
|
|
|
|
orgPayload := overview.RecentJobs[1].Payload
|
|
require.Equal(t, "people-growth", orgPayload["matchLocalPart"])
|
|
require.NotContains(t, orgPayload, "request")
|
|
require.Equal(t, domain.JSONMap{
|
|
"email": "people-growth@example.com",
|
|
"orgUnitName": "인재성장",
|
|
"orgUnitExternalKey": "org-1",
|
|
"parentOrgUnitId": "externalKey:parent-1",
|
|
}, orgPayload["requestSummary"])
|
|
}
|
|
|
|
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,
|
|
}
|
|
userGroup := domain.Tenant{
|
|
ID: "legacy-user-group-tenant",
|
|
Name: "사용자 그룹 조직",
|
|
Type: domain.TenantTypeUserGroup,
|
|
ParentID: &hanmac.ID,
|
|
}
|
|
|
|
items := compareWorksmobileGroups(
|
|
[]domain.Tenant{root, hanmac, barongroup, barongroupChildCompany, organization, userGroup},
|
|
[]WorksmobileRemoteGroup{
|
|
{ID: "works-root", ExternalID: root.ID, DisplayName: root.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, ParentID: "works-hanmac"},
|
|
{ID: "works-user-group", ExternalID: userGroup.ID, DisplayName: userGroup.Name, ParentID: "works-hanmac"},
|
|
{ID: "works-orphan", ExternalID: "works-orphan", DisplayName: "WORKS 전용 조직"},
|
|
},
|
|
true,
|
|
)
|
|
|
|
require.Len(t, items, 4)
|
|
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-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, userGroup.ID, items[2].BaronID)
|
|
require.Equal(t, "matched", items[2].Status)
|
|
require.Equal(t, "works-orphan", items[3].ExternalKey)
|
|
require.Equal(t, "missing_in_baron", items[3].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileGroupsShowsUserGroupMissingInWorksmobile(t *testing.T) {
|
|
parentID := "company-tenant"
|
|
userGroup := domain.Tenant{
|
|
ID: "team-tenant",
|
|
Name: "신규 팀",
|
|
Slug: "new-team",
|
|
Type: domain.TenantTypeUserGroup,
|
|
ParentID: &parentID,
|
|
}
|
|
|
|
items := compareWorksmobileGroups(
|
|
[]domain.Tenant{
|
|
{ID: parentID, Slug: "company", Name: "계열사", Type: domain.TenantTypeCompany},
|
|
userGroup,
|
|
},
|
|
nil,
|
|
false,
|
|
)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, userGroup.ID, items[0].BaronID)
|
|
require.Equal(t, "missing_in_worksmobile", items[0].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileGroupsMarksMatchedOrgUnitNeedsUpdate(t *testing.T) {
|
|
parentID := "parent-tenant"
|
|
tenant := domain.Tenant{
|
|
ID: "team-tenant",
|
|
Name: "변경된 팀명",
|
|
Slug: "team",
|
|
Type: domain.TenantTypeUserGroup,
|
|
ParentID: &parentID,
|
|
}
|
|
|
|
items := compareWorksmobileGroups(
|
|
[]domain.Tenant{
|
|
{ID: parentID, Slug: "parent", Name: "상위 조직", Type: domain.TenantTypeUserGroup},
|
|
tenant,
|
|
},
|
|
[]WorksmobileRemoteGroup{
|
|
{ID: "works-parent", ExternalID: parentID, DisplayName: "상위 조직"},
|
|
{ID: "works-team", ExternalID: tenant.ID, DisplayName: "이전 팀명", ParentID: "works-parent"},
|
|
},
|
|
false,
|
|
)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, tenant.ID, items[0].BaronID)
|
|
require.Equal(t, "needs_update", items[0].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileGroupsCoversHanmacOrganizationRegressionIDs(t *testing.T) {
|
|
rootID := "038326b6-954a-48a7-a85f-efd83f62b82a"
|
|
samanID := "9caf62e1-297d-4e8f-870b-61780998bbeb"
|
|
hanmacID := "369c1843-56af-4344-9c21-0e01197ab861"
|
|
baronGroupID := "96369f12-6b66-4b2a-a916-d1c99d326f02"
|
|
changedID := "818c856b-9545-442f-b827-d1c569f200b0"
|
|
hanmacOnlyID := "2d217948-9c5a-42ea-805b-eef9c7421775"
|
|
baronOnlyID := "32464fd6-da51-473f-844a-ab88603ad1f0"
|
|
localTenants := []domain.Tenant{
|
|
{ID: rootID, Slug: HanmacFamilyTenantSlug, Name: "한맥가족", Type: domain.TenantTypeCompanyGroup},
|
|
{ID: samanID, Slug: "saman", Name: "삼안", Type: domain.TenantTypeCompany, ParentID: &rootID},
|
|
{ID: hanmacID, Slug: "hanmac", Name: "한맥기술", Type: domain.TenantTypeCompany, ParentID: &rootID},
|
|
{ID: baronGroupID, Slug: "baron-group", Name: "바론그룹", Type: domain.TenantTypeCompanyGroup, ParentID: &rootID},
|
|
{ID: changedID, Slug: "rnd-saman", Name: "삼안기술개발센터(조직도용)", Type: domain.TenantTypeOrganization, ParentID: &samanID},
|
|
{ID: hanmacOnlyID, Slug: "rnd-hanmac", Name: "한맥기술개발센터(조직도용)", Type: domain.TenantTypeOrganization, ParentID: &hanmacID},
|
|
{ID: baronOnlyID, Slug: "rnd-baron", Name: "바론기술개발센터(조직도용)", Type: domain.TenantTypeOrganization, ParentID: &baronGroupID},
|
|
}
|
|
remoteGroups := []WorksmobileRemoteGroup{
|
|
{ID: "works-saman", ExternalID: samanID, DisplayName: "삼안"},
|
|
{ID: "works-hanmac", ExternalID: hanmacID, DisplayName: "한맥기술"},
|
|
{
|
|
ID: "works-rnd-saman",
|
|
ExternalID: changedID,
|
|
DisplayName: "삼안기술개발센터(조직도용)",
|
|
},
|
|
}
|
|
|
|
items := compareWorksmobileGroups(localTenants, remoteGroups, false)
|
|
itemsByBaronID := map[string]WorksmobileComparisonItem{}
|
|
for _, item := range items {
|
|
itemsByBaronID[item.BaronID] = item
|
|
}
|
|
|
|
require.Equal(t, "needs_update", itemsByBaronID[changedID].Status)
|
|
require.Equal(t, "missing_in_worksmobile", itemsByBaronID[hanmacOnlyID].Status)
|
|
require.Equal(t, "missing_in_worksmobile", itemsByBaronID[baronOnlyID].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileGroupsDoesNotMatchBaronGroupOrganizationInGPDTDCDomain(t *testing.T) {
|
|
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
|
|
t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
|
|
rootID := "038326b6-954a-48a7-a85f-efd83f62b82a"
|
|
baronGroupID := "96369f12-6b66-4b2a-a916-d1c99d326f02"
|
|
orgID := "32464fd6-da51-473f-844a-ab88603ad1f0"
|
|
localTenants := []domain.Tenant{
|
|
{ID: rootID, Slug: HanmacFamilyTenantSlug, Name: "한맥가족", Type: domain.TenantTypeCompanyGroup},
|
|
{ID: baronGroupID, Slug: "baron-group", Name: "바론그룹", Type: domain.TenantTypeCompanyGroup, ParentID: &rootID},
|
|
{ID: orgID, Slug: "rnd-baron", Name: "바론기술개발센터(조직도용)", Type: domain.TenantTypeOrganization, ParentID: &baronGroupID},
|
|
}
|
|
remoteGroups := []WorksmobileRemoteGroup{
|
|
{
|
|
ID: "works-rnd-baron-gpdtdc",
|
|
ExternalID: orgID,
|
|
DisplayName: "바론기술개발센터(조직도용)",
|
|
DomainID: 1003,
|
|
DomainName: "총괄기획&기술개발센터",
|
|
},
|
|
}
|
|
|
|
items := compareWorksmobileGroups(localTenants, remoteGroups, false)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, orgID, items[0].BaronID)
|
|
require.Equal(t, "missing_in_worksmobile", items[0].Status)
|
|
require.Empty(t, items[0].WorksmobileID)
|
|
}
|
|
|
|
func TestCompareWorksmobileGroupsMatchesBaronGroupOrganizationInBaronGroupDomain(t *testing.T) {
|
|
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
|
|
t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
|
|
rootID := "038326b6-954a-48a7-a85f-efd83f62b82a"
|
|
baronGroupID := "96369f12-6b66-4b2a-a916-d1c99d326f02"
|
|
orgID := "32464fd6-da51-473f-844a-ab88603ad1f0"
|
|
localTenants := []domain.Tenant{
|
|
{ID: rootID, Slug: HanmacFamilyTenantSlug, Name: "한맥가족", Type: domain.TenantTypeCompanyGroup},
|
|
{ID: baronGroupID, Slug: "baron-group", Name: "바론그룹", Type: domain.TenantTypeCompanyGroup, ParentID: &rootID},
|
|
{ID: orgID, Slug: "rnd-baron", Name: "바론기술개발센터(조직도용)", Type: domain.TenantTypeOrganization, ParentID: &baronGroupID},
|
|
}
|
|
remoteGroups := []WorksmobileRemoteGroup{
|
|
{
|
|
ID: "works-rnd-baron",
|
|
ExternalID: orgID,
|
|
DisplayName: "바론기술개발센터(조직도용)",
|
|
DomainID: 1004,
|
|
DomainName: "바론그룹",
|
|
},
|
|
}
|
|
|
|
diffOnly := compareWorksmobileGroups(localTenants, remoteGroups, false)
|
|
all := compareWorksmobileGroups(localTenants, remoteGroups, true)
|
|
|
|
require.Empty(t, diffOnly)
|
|
require.Len(t, all, 1)
|
|
require.Equal(t, orgID, all[0].BaronID)
|
|
require.Equal(t, "matched", all[0].Status)
|
|
require.Equal(t, int64(1004), all[0].WorksmobileDomainID)
|
|
}
|
|
|
|
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)
|
|
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 TestWorksmobileSyncServiceUsesBaronGroupDomainForBaronGroupChildOrganization(t *testing.T) {
|
|
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
|
|
t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
|
|
rootID := "038326b6-954a-48a7-a85f-efd83f62b82a"
|
|
baronGroupID := "96369f12-6b66-4b2a-a916-d1c99d326f02"
|
|
orgID := "32464fd6-da51-473f-844a-ab88603ad1f0"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
Type: domain.TenantTypeCompanyGroup,
|
|
}
|
|
baronGroup := domain.Tenant{
|
|
ID: baronGroupID,
|
|
Slug: "baron-group",
|
|
Name: "바론그룹",
|
|
Type: domain.TenantTypeCompanyGroup,
|
|
ParentID: &rootID,
|
|
}
|
|
organization := domain.Tenant{
|
|
ID: orgID,
|
|
Slug: "rnd-baron",
|
|
Name: "바론기술개발센터(조직도용)",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &baronGroupID,
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{
|
|
tenants: map[string]domain.Tenant{
|
|
root.ID: root,
|
|
baronGroup.ID: baronGroup,
|
|
organization.ID: organization,
|
|
},
|
|
list: []domain.Tenant{root, baronGroup, 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, int64(1004), request.DomainID)
|
|
require.Equal(t, "rnd-baron@brsw.kr", request.Email)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceUsesGPDTDCDomainForGPDTDCChildOrganization(t *testing.T) {
|
|
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
|
|
t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
|
|
rootID := "038326b6-954a-48a7-a85f-efd83f62b82a"
|
|
gpdtdcID := "5530ca6e-c5e6-4bf0-84d6-76c6a8fb70ee"
|
|
orgID := "gpdtdc-child-organization"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
Type: domain.TenantTypeCompanyGroup,
|
|
}
|
|
gpdtdc := domain.Tenant{
|
|
ID: gpdtdcID,
|
|
Slug: "gpdtdc",
|
|
Name: "총괄기획&기술개발센터",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &rootID,
|
|
}
|
|
organization := domain.Tenant{
|
|
ID: orgID,
|
|
Slug: "planning",
|
|
Name: "기획",
|
|
Type: domain.TenantTypeOrganization,
|
|
ParentID: &gpdtdcID,
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{
|
|
tenants: map[string]domain.Tenant{
|
|
root.ID: root,
|
|
gpdtdc.ID: gpdtdc,
|
|
organization.ID: organization,
|
|
},
|
|
list: []domain.Tenant{root, gpdtdc, 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, int64(1003), request.DomainID)
|
|
require.Equal(t, "planning@baroncs.co.kr", request.Email)
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceSkipsArchivedUsersInComparison(t *testing.T) {
|
|
rootID := "root-tenant"
|
|
companyID := "company-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Name: "계열사",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
}
|
|
archived := domain.User{
|
|
ID: "archived-user",
|
|
Email: "archived@samaneng.com",
|
|
Name: "Archived",
|
|
TenantID: &companyID,
|
|
Status: domain.UserStatusArchived,
|
|
}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root, companyID: company}, list: []domain.Tenant{root, company}},
|
|
&fakeWorksmobileUserRepo{byTenant: []domain.User{archived}},
|
|
&fakeWorksmobileOutboxRepo{},
|
|
&fakeWorksmobileDirectoryClient{users: []WorksmobileRemoteUser{{
|
|
ID: "works-archived",
|
|
ExternalID: archived.ID,
|
|
Email: archived.Email,
|
|
}}},
|
|
)
|
|
|
|
comparison, err := service.GetComparison(context.Background(), rootID, true)
|
|
|
|
require.NoError(t, err)
|
|
require.Empty(t, comparison.Users)
|
|
}
|
|
|
|
func TestWorksmobileSyncServiceBackfillDryRunSkipsArchivedUsers(t *testing.T) {
|
|
rootID := "root-tenant"
|
|
companyID := "company-tenant"
|
|
root := domain.Tenant{
|
|
ID: rootID,
|
|
Slug: HanmacFamilyTenantSlug,
|
|
Name: "한맥가족",
|
|
}
|
|
company := domain.Tenant{
|
|
ID: companyID,
|
|
Name: "계열사",
|
|
Type: domain.TenantTypeCompany,
|
|
ParentID: &rootID,
|
|
}
|
|
active := domain.User{
|
|
ID: "active-user",
|
|
Email: "active@samaneng.com",
|
|
Name: "Active",
|
|
TenantID: &companyID,
|
|
Status: domain.UserStatusActive,
|
|
}
|
|
archived := domain.User{
|
|
ID: "archived-user",
|
|
Email: "archived@samaneng.com",
|
|
Name: "Archived",
|
|
TenantID: &companyID,
|
|
Status: domain.UserStatusArchived,
|
|
}
|
|
outboxRepo := &fakeWorksmobileOutboxRepo{}
|
|
service := NewWorksmobileSyncService(
|
|
&fakeWorksmobileTenantService{tenants: map[string]domain.Tenant{rootID: root, companyID: company}, list: []domain.Tenant{root, company}},
|
|
&fakeWorksmobileUserRepo{byTenant: []domain.User{active, archived}},
|
|
outboxRepo,
|
|
nil,
|
|
)
|
|
|
|
dryRun, err := service.EnqueueBackfillDryRun(context.Background(), rootID)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, dryRun.UserCount)
|
|
require.Len(t, outboxRepo.created, 1)
|
|
require.Equal(t, 1, outboxRepo.created[0].Payload["userCount"])
|
|
}
|
|
|
|
func TestCompareWorksmobileUsersMarksManagerChangeNeedsUpdate(t *testing.T) {
|
|
tenantID := "tenant-leaf"
|
|
user := domain.User{
|
|
ID: "user-manager",
|
|
Email: "manager@samaneng.com",
|
|
Name: "Manager User",
|
|
TenantID: &tenantID,
|
|
Status: domain.UserStatusActive,
|
|
Metadata: domain.JSONMap{
|
|
"additionalAppointments": []any{
|
|
map[string]any{
|
|
"tenantId": tenantID,
|
|
"isPrimary": true,
|
|
"isManager": true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
remoteManager := false
|
|
items := compareWorksmobileUsers(
|
|
[]domain.User{user},
|
|
[]WorksmobileRemoteUser{{
|
|
ID: "works-user-manager",
|
|
ExternalID: user.ID,
|
|
Email: user.Email,
|
|
DisplayName: user.Name,
|
|
PrimaryOrgUnitID: "externalKey:" + tenantID,
|
|
PrimaryOrgUnitIsManager: &remoteManager,
|
|
}},
|
|
true,
|
|
map[string]domain.Tenant{
|
|
tenantID: {ID: tenantID, Name: "Leaf", Type: domain.TenantTypeOrganization},
|
|
},
|
|
)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, "needs_update", items[0].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileUsersMarksSecondaryManagerChangeNeedsUpdate(t *testing.T) {
|
|
primaryTenantID := "tenant-company"
|
|
secondaryTenantID := "tenant-gpdtdc-leaf"
|
|
user := domain.User{
|
|
ID: "user-secondary-manager",
|
|
Email: "secondary-manager@samaneng.com",
|
|
Name: "Secondary Manager User",
|
|
TenantID: &secondaryTenantID,
|
|
Status: domain.UserStatusActive,
|
|
Metadata: domain.JSONMap{
|
|
"additionalAppointments": []any{
|
|
map[string]any{
|
|
"tenantId": primaryTenantID,
|
|
"isPrimary": true,
|
|
},
|
|
map[string]any{
|
|
"tenantId": secondaryTenantID,
|
|
"isPrimary": false,
|
|
"isManager": true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
remotePrimaryManager := false
|
|
remoteSecondaryManager := false
|
|
items := compareWorksmobileUsers(
|
|
[]domain.User{user},
|
|
[]WorksmobileRemoteUser{{
|
|
ID: "works-user-secondary-manager",
|
|
ExternalID: user.ID,
|
|
Email: user.Email,
|
|
DisplayName: user.Name,
|
|
PrimaryOrgUnitID: "externalKey:" + primaryTenantID,
|
|
PrimaryOrgUnitIsManager: &remotePrimaryManager,
|
|
OrgUnitManagers: map[string]*bool{
|
|
"externalKey:" + primaryTenantID: &remotePrimaryManager,
|
|
"externalKey:" + secondaryTenantID: &remoteSecondaryManager,
|
|
},
|
|
}},
|
|
true,
|
|
map[string]domain.Tenant{
|
|
primaryTenantID: {ID: primaryTenantID, Name: "Company", Type: domain.TenantTypeCompany},
|
|
secondaryTenantID: {ID: secondaryTenantID, Name: "GPDTDC Leaf", Type: domain.TenantTypeOrganization},
|
|
},
|
|
)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, "needs_update", items[0].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileUsersMarksMissingSecondaryOrganizationNeedsUpdate(t *testing.T) {
|
|
t.Setenv("SAMAN_DOMAIN_ID", "1001")
|
|
t.Setenv("GPDTDC_DOMAIN_ID", "1003")
|
|
rootID := "tenant-root"
|
|
primaryTenantID := "tenant-saman"
|
|
gpdtdcID := "tenant-gpdtdc"
|
|
secondaryTenantID := "tenant-gpdtdc-leaf"
|
|
user := domain.User{
|
|
ID: "user-secondary-org",
|
|
Email: "secondary-org@samaneng.com",
|
|
Name: "Secondary Org User",
|
|
TenantID: &secondaryTenantID,
|
|
Status: domain.UserStatusActive,
|
|
Metadata: domain.JSONMap{
|
|
"additionalAppointments": []any{
|
|
map[string]any{
|
|
"tenantId": primaryTenantID,
|
|
"isPrimary": true,
|
|
},
|
|
map[string]any{
|
|
"tenantId": secondaryTenantID,
|
|
"isPrimary": false,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
remotePrimaryManager := false
|
|
items := compareWorksmobileUsers(
|
|
[]domain.User{user},
|
|
[]WorksmobileRemoteUser{{
|
|
ID: "works-user-secondary-org",
|
|
ExternalID: user.ID,
|
|
Email: user.Email,
|
|
DisplayName: user.Name,
|
|
Organizations: []WorksmobileUserOrganization{
|
|
{
|
|
DomainID: 1001,
|
|
Email: user.Email,
|
|
Primary: true,
|
|
OrgUnits: []WorksmobileUserOrgUnit{
|
|
{
|
|
OrgUnitID: "externalKey:" + primaryTenantID,
|
|
Primary: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
PrimaryOrgUnitID: "externalKey:" + primaryTenantID,
|
|
PrimaryOrgUnitIsManager: &remotePrimaryManager,
|
|
}},
|
|
true,
|
|
map[string]domain.Tenant{
|
|
rootID: {ID: rootID, Slug: HanmacFamilyTenantSlug, Name: "한맥가족", Type: domain.TenantTypeCompanyGroup},
|
|
primaryTenantID: {ID: primaryTenantID, Slug: "saman", Name: "삼안", Type: domain.TenantTypeCompany, ParentID: &rootID, Domains: []domain.TenantDomain{{Domain: "samaneng.com"}}},
|
|
gpdtdcID: {ID: gpdtdcID, Slug: "gpdtdc", Name: "총괄기획&기술개발센터", Type: domain.TenantTypeCompanyGroup, ParentID: &rootID},
|
|
secondaryTenantID: {ID: secondaryTenantID, Slug: "people-growth", Name: "인재성장", Type: domain.TenantTypeOrganization, ParentID: &gpdtdcID},
|
|
},
|
|
)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, "needs_update", items[0].Status)
|
|
}
|
|
|
|
func TestCompareWorksmobileUsersMarksPhoneAndEmployeeNumberChangesNeedsUpdate(t *testing.T) {
|
|
tenantID := "tenant-saman"
|
|
user := domain.User{
|
|
ID: "user-phone-employee",
|
|
Email: "phone-employee@samaneng.com",
|
|
Name: "Phone Employee User",
|
|
Phone: "010-1234-5678",
|
|
TenantID: &tenantID,
|
|
Status: domain.UserStatusActive,
|
|
Metadata: domain.JSONMap{
|
|
"employeeNumber": "EMP001",
|
|
},
|
|
}
|
|
items := compareWorksmobileUsers(
|
|
[]domain.User{user},
|
|
[]WorksmobileRemoteUser{{
|
|
ID: "works-user-phone-employee",
|
|
ExternalID: user.ID,
|
|
Email: user.Email,
|
|
DisplayName: user.Name,
|
|
CellPhone: "+821099998888",
|
|
EmployeeNumber: "EMP999",
|
|
}},
|
|
true,
|
|
map[string]domain.Tenant{
|
|
tenantID: {ID: tenantID, Name: "삼안", Type: domain.TenantTypeCompany},
|
|
},
|
|
)
|
|
|
|
require.Len(t, items, 1)
|
|
require.Equal(t, "needs_update", items[0].Status)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (f *fakeWorksmobileUserRepo) DB() *gorm.DB {
|
|
return nil
|
|
}
|