forked from baron/baron-sso
240 lines
8.0 KiB
Go
240 lines
8.0 KiB
Go
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)
|
|
}
|