forked from baron/baron-sso
조직도 기능 추가
This commit is contained in:
239
backend/internal/service/org_chart_service_test.go
Normal file
239
backend/internal/service/org_chart_service_test.go
Normal file
@@ -0,0 +1,239 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"baron-sso-backend/internal/domain"
|
||||
"baron-sso-backend/internal/repository"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
||||
type mockTenantRepo struct {
|
||||
mock.Mock
|
||||
repository.TenantRepository
|
||||
}
|
||||
|
||||
func (m *mockTenantRepo) FindBySlug(ctx context.Context, slug string) (*domain.Tenant, error) {
|
||||
args := m.Called(ctx, slug)
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
return args.Get(0).(*domain.Tenant), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockTenantRepo) Create(ctx context.Context, tenant *domain.Tenant) error {
|
||||
args := m.Called(ctx, tenant)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *mockTenantRepo) AddDomain(ctx context.Context, tenantID, domainName string, isPrimary bool) error {
|
||||
args := m.Called(ctx, tenantID, domainName, isPrimary)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type mockUserGroupRepo struct {
|
||||
mock.Mock
|
||||
repository.UserGroupRepository
|
||||
}
|
||||
|
||||
func (m *mockUserGroupRepo) ListByTenantID(ctx context.Context, tenantID string) ([]domain.UserGroup, error) {
|
||||
args := m.Called(ctx, tenantID)
|
||||
return args.Get(0).([]domain.UserGroup), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockUserGroupRepo) Create(ctx context.Context, ug *domain.UserGroup) error {
|
||||
args := m.Called(ctx, ug)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type mockUserRepo struct {
|
||||
mock.Mock
|
||||
repository.UserRepository
|
||||
}
|
||||
|
||||
func (m *mockUserRepo) Update(ctx context.Context, user *domain.User) error {
|
||||
args := m.Called(ctx, user)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type mockKetoOutboxRepo struct {
|
||||
mock.Mock
|
||||
repository.KetoOutboxRepository
|
||||
}
|
||||
|
||||
func (m *mockKetoOutboxRepo) Create(ctx context.Context, outbox *domain.KetoOutbox) error {
|
||||
args := m.Called(ctx, outbox)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type mockKratosService struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *mockKratosService) ListIdentities(ctx context.Context) ([]KratosIdentity, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *mockKratosService) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
|
||||
args := m.Called(ctx, identifier)
|
||||
return args.String(0), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockKratosService) GetIdentity(ctx context.Context, identityID string) (*KratosIdentity, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *mockKratosService) UpdateIdentity(ctx context.Context, id string, traits map[string]interface{}, state string) (*KratosIdentity, error) {
|
||||
args := m.Called(ctx, id, traits, state)
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockKratosService) UpdateIdentityPassword(ctx context.Context, id, pw string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockKratosService) DeleteIdentity(ctx context.Context, id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockKratosService) CreateUser(ctx context.Context, user *domain.BrokerUser, password string) (string, error) {
|
||||
args := m.Called(ctx, user, password)
|
||||
return args.String(0), args.Error(1)
|
||||
}
|
||||
|
||||
func setupMocksForImport(tenantRepo *mockTenantRepo, ugRepo *mockUserGroupRepo, userRepo *mockUserRepo, ketoRepo *mockKetoOutboxRepo, kratos *mockKratosService, ctx context.Context, companySlug, email string) {
|
||||
tenantRepo.On("FindBySlug", ctx, companySlug).Return(&domain.Tenant{ID: companySlug + "-id", Slug: companySlug}, nil).Maybe()
|
||||
tenantRepo.On("FindBySlug", ctx, mock.Anything).Return(&domain.Tenant{ID: "fallback-id", Slug: "fallback"}, nil).Maybe()
|
||||
tenantRepo.On("AddDomain", ctx, mock.Anything, mock.Anything, true).Return(nil).Maybe()
|
||||
tenantRepo.On("Create", ctx, mock.Anything).Return(nil).Maybe()
|
||||
ugRepo.On("ListByTenantID", ctx, mock.Anything).Return([]domain.UserGroup{}, nil).Maybe()
|
||||
ugRepo.On("Create", ctx, mock.Anything).Return(nil).Maybe()
|
||||
kratos.On("FindIdentityIDByIdentifier", ctx, email).Return("user-id", nil).Maybe()
|
||||
kratos.On("UpdateIdentity", ctx, "user-id", mock.Anything, "active").Return(nil, nil).Maybe()
|
||||
userRepo.On("Update", ctx, mock.Anything).Return(nil).Maybe()
|
||||
ketoRepo.On("Create", ctx, mock.Anything).Return(nil).Maybe()
|
||||
}
|
||||
|
||||
func TestImportOrgChart_CSV_BOM(t *testing.T) {
|
||||
tenantRepo := new(mockTenantRepo)
|
||||
ugRepo := new(mockUserGroupRepo)
|
||||
userRepo := new(mockUserRepo)
|
||||
ketoRepo := new(mockKetoOutboxRepo)
|
||||
kratos := new(mockKratosService)
|
||||
svc := NewOrgChartService(tenantRepo, ugRepo, userRepo, ketoRepo, kratos)
|
||||
|
||||
csvData := "\xef\xbb\xbf이메일,이름,소속,직급,그룹,디비젼,팀,구분\n" +
|
||||
"test@example.com,홍길동,한맥,사원,엔지니어링,구조,계획,팀원"
|
||||
|
||||
ctx := context.Background()
|
||||
setupMocksForImport(tenantRepo, ugRepo, userRepo, ketoRepo, kratos, ctx, "hanmac", "test@example.com")
|
||||
|
||||
res, err := svc.ImportOrgChart(ctx, "root-id", bytes.NewReader([]byte(csvData)), "test.csv", "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
}
|
||||
|
||||
func TestImportOrgChart_XLSX(t *testing.T) {
|
||||
tenantRepo := new(mockTenantRepo)
|
||||
ugRepo := new(mockUserGroupRepo)
|
||||
userRepo := new(mockUserRepo)
|
||||
ketoRepo := new(mockKetoOutboxRepo)
|
||||
kratos := new(mockKratosService)
|
||||
svc := NewOrgChartService(tenantRepo, ugRepo, userRepo, ketoRepo, kratos)
|
||||
|
||||
xlsx := excelize.NewFile()
|
||||
xlsx.SetCellValue("Sheet1", "A1", "이메일")
|
||||
xlsx.SetCellValue("Sheet1", "B1", "이름")
|
||||
xlsx.SetCellValue("Sheet1", "C1", "소속")
|
||||
xlsx.SetCellValue("Sheet1", "A2", "xlsx@example.com")
|
||||
xlsx.SetCellValue("Sheet1", "B2", "엑셀맨")
|
||||
xlsx.SetCellValue("Sheet1", "C2", "삼안")
|
||||
|
||||
var buf bytes.Buffer
|
||||
xlsx.Write(&buf)
|
||||
|
||||
ctx := context.Background()
|
||||
setupMocksForImport(tenantRepo, ugRepo, userRepo, ketoRepo, kratos, ctx, "saman", "xlsx@example.com")
|
||||
|
||||
res, err := svc.ImportOrgChart(ctx, "root-id", &buf, "test.xlsx", "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
}
|
||||
|
||||
func TestImportOrgChart_MissingColumns(t *testing.T) {
|
||||
svc := NewOrgChartService(nil, nil, nil, nil, nil)
|
||||
ctx := context.Background()
|
||||
|
||||
csvData := "소속,직급\n한맥,부장"
|
||||
res, err := svc.ImportOrgChart(ctx, "root", bytes.NewReader([]byte(csvData)), "test.csv", "")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, res)
|
||||
}
|
||||
|
||||
func TestImportOrgChart_RobustHeader(t *testing.T) {
|
||||
tenantRepo := new(mockTenantRepo)
|
||||
ugRepo := new(mockUserGroupRepo)
|
||||
userRepo := new(mockUserRepo)
|
||||
ketoRepo := new(mockKetoOutboxRepo)
|
||||
kratos := new(mockKratosService)
|
||||
svc := NewOrgChartService(tenantRepo, ugRepo, userRepo, ketoRepo, kratos)
|
||||
|
||||
csvData := "\n\n 이 메 일 , 이 름 , 소 속 \n" +
|
||||
"robust@example.com,로버스트,바론"
|
||||
ctx := context.Background()
|
||||
setupMocksForImport(tenantRepo, ugRepo, userRepo, ketoRepo, kratos, ctx, "baron", "robust@example.com")
|
||||
|
||||
res, err := svc.ImportOrgChart(ctx, "root-id", bytes.NewReader([]byte(csvData)), "test.csv", "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
}
|
||||
|
||||
func TestImportOrgChart_MultiSheet_ComplexHeaders(t *testing.T) {
|
||||
tenantRepo := new(mockTenantRepo)
|
||||
ugRepo := new(mockUserGroupRepo)
|
||||
userRepo := new(mockUserRepo)
|
||||
ketoRepo := new(mockKetoOutboxRepo)
|
||||
kratos := new(mockKratosService)
|
||||
svc := NewOrgChartService(tenantRepo, ugRepo, userRepo, ketoRepo, kratos)
|
||||
|
||||
xlsx := excelize.NewFile()
|
||||
xlsx.NewSheet("Sheet2")
|
||||
xlsx.SetCellValue("Sheet2", "A3", " 이 메 일 ")
|
||||
xlsx.SetCellValue("Sheet2", "B3", " 성 함 / 이 름 ")
|
||||
xlsx.SetCellValue("Sheet2", "C3", " 소 속 회 사 ")
|
||||
xlsx.SetCellValue("Sheet2", "A4", "sheet2@example.com")
|
||||
xlsx.SetCellValue("Sheet2", "B4", "시트투")
|
||||
xlsx.SetCellValue("Sheet2", "C4", "한맥")
|
||||
|
||||
var buf bytes.Buffer
|
||||
xlsx.Write(&buf)
|
||||
|
||||
ctx := context.Background()
|
||||
setupMocksForImport(tenantRepo, ugRepo, userRepo, ketoRepo, kratos, ctx, "hanmac", "sheet2@example.com")
|
||||
|
||||
res, err := svc.ImportOrgChart(ctx, "root-id", &buf, "test.xlsx", "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
}
|
||||
|
||||
func TestImportOrgChart_MessyHeader(t *testing.T) {
|
||||
tenantRepo := new(mockTenantRepo)
|
||||
ugRepo := new(mockUserGroupRepo)
|
||||
userRepo := new(mockUserRepo)
|
||||
ketoRepo := new(mockKetoOutboxRepo)
|
||||
kratos := new(mockKratosService)
|
||||
svc := NewOrgChartService(tenantRepo, ugRepo, userRepo, ketoRepo, kratos)
|
||||
|
||||
csvData := " 이메일(ID)* , 성 명 , [소속] \n" +
|
||||
"messy@example.com,메시,바론"
|
||||
ctx := context.Background()
|
||||
setupMocksForImport(tenantRepo, ugRepo, userRepo, ketoRepo, kratos, ctx, "baron", "messy@example.com")
|
||||
|
||||
res, err := svc.ImportOrgChart(ctx, "root-id", bytes.NewReader([]byte(csvData)), "test.csv", "")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
}
|
||||
Reference in New Issue
Block a user