forked from baron/baron-sso
조직도 M2M조회 추가, 자동로그인 보완
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -213,6 +214,13 @@ func (m *MockUserProjectionRepoForHandler) MarkFailed(ctx context.Context, syncE
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func toJSONString(t *testing.T, value any) string {
|
||||
t.Helper()
|
||||
raw, err := json.Marshal(value)
|
||||
require.NoError(t, err)
|
||||
return string(raw)
|
||||
}
|
||||
|
||||
func TestTenantHandler_CreateTenant(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockSvc := new(MockTenantService)
|
||||
@@ -360,6 +368,121 @@ func TestTenantHandler_ListTenants(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTenantHandler_GetOrgContextJSONDefaultsToHanmacFamilyForApiKey(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockSvc := new(MockTenantService)
|
||||
mockUsers := new(MockUserRepoForHandler)
|
||||
h := &TenantHandler{Service: mockSvc, UserRepo: mockUsers}
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
c.Locals("apiKeyName", "orgfront-ssot-client")
|
||||
return c.Next()
|
||||
})
|
||||
app.Get("/org-context", h.GetOrgContext)
|
||||
|
||||
now := time.Date(2026, 5, 13, 12, 0, 0, 0, time.UTC)
|
||||
parent := func(id string) *string { return &id }
|
||||
tenants := []domain.Tenant{
|
||||
{ID: "root-other", Type: domain.TenantTypeCompanyGroup, Name: "다른그룹", Slug: "other-family", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "group-hanmac-family", Type: domain.TenantTypeCompanyGroup, Name: "한맥가족", Slug: "hanmac-family", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "company-hanmac", Type: domain.TenantTypeCompany, ParentID: parent("group-hanmac-family"), Name: "한맥기술", Slug: "hanmac", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "dept-platform", Type: domain.TenantTypeUserGroup, ParentID: parent("company-hanmac"), Name: "플랫폼실", Slug: "platform", Status: domain.TenantStatusActive, Config: domain.JSONMap{"orgUnitType": "실"}, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "team-sso", Type: domain.TenantTypeUserGroup, ParentID: parent("dept-platform"), Name: "SSO팀", Slug: "sso", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "private-team", Type: domain.TenantTypeUserGroup, ParentID: parent("company-hanmac"), Name: "비공개", Slug: "private-team", Status: domain.TenantStatusActive, Config: domain.JSONMap{"visibility": "private"}, CreatedAt: now, UpdatedAt: now},
|
||||
}
|
||||
usersByTenantID := []domain.User{
|
||||
{ID: "user-platform-lead", Email: "lead@example.com", Name: "플랫폼 리드", Status: domain.UserStatusActive, TenantID: parent("dept-platform"), CompanyCode: "platform", Grade: "책임", Position: "실장", CreatedAt: now, UpdatedAt: now},
|
||||
}
|
||||
usersBySlug := []domain.User{
|
||||
{ID: "user-sso-member", Email: "member@example.com", Name: "SSO 구성원", Status: domain.UserStatusActive, CompanyCode: "sso", Grade: "선임", CreatedAt: now, UpdatedAt: now},
|
||||
}
|
||||
|
||||
mockSvc.On("ListTenants", mock.Anything, 10000, 0, "").Return(tenants, int64(len(tenants)), nil)
|
||||
mockUsers.On("FindByTenantIDs", mock.Anything, []string{"group-hanmac-family", "company-hanmac", "dept-platform", "team-sso"}).Return(usersByTenantID, nil)
|
||||
mockUsers.On("FindByCompanyCodes", mock.Anything, []string{"hanmac-family", "hanmac", "platform", "sso"}).Return(usersBySlug, nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/org-context", nil)
|
||||
resp, err := app.Test(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var got map[string]any
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&got))
|
||||
require.Equal(t, "baron.org-context.v1", got["schemaVersion"])
|
||||
|
||||
scope := got["scope"].(map[string]any)
|
||||
require.Equal(t, "group-hanmac-family", scope["tenantId"])
|
||||
require.Equal(t, "hanmac-family", scope["tenantSlug"])
|
||||
|
||||
tenantsPayload := got["tenants"].([]any)
|
||||
require.Len(t, tenantsPayload, 4)
|
||||
require.Equal(t, "group-hanmac-family", tenantsPayload[0].(map[string]any)["id"])
|
||||
require.Equal(t, "company-hanmac", tenantsPayload[1].(map[string]any)["id"])
|
||||
require.Equal(t, "dept-platform", tenantsPayload[2].(map[string]any)["id"])
|
||||
require.Equal(t, "team-sso", tenantsPayload[3].(map[string]any)["id"])
|
||||
|
||||
usersPayload := got["users"].([]any)
|
||||
require.Len(t, usersPayload, 2)
|
||||
require.Equal(t, "user-platform-lead", usersPayload[0].(map[string]any)["id"])
|
||||
require.Equal(t, []any{"dept-platform"}, usersPayload[0].(map[string]any)["tenantIds"])
|
||||
require.Equal(t, "user-sso-member", usersPayload[1].(map[string]any)["id"])
|
||||
|
||||
tree := got["tree"].(map[string]any)
|
||||
require.Equal(t, "group-hanmac-family", tree["id"])
|
||||
require.NotContains(t, toJSONString(t, got), "private-team")
|
||||
require.NotContains(t, toJSONString(t, got), "root-other")
|
||||
}
|
||||
|
||||
func TestTenantHandler_GetOrgContextJSONScopesByTenantSlug(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockSvc := new(MockTenantService)
|
||||
mockUsers := new(MockUserRepoForHandler)
|
||||
h := &TenantHandler{Service: mockSvc, UserRepo: mockUsers}
|
||||
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
c.Locals("apiKeyName", "orgfront-ssot-client")
|
||||
return c.Next()
|
||||
})
|
||||
app.Get("/org-context", h.GetOrgContext)
|
||||
|
||||
now := time.Date(2026, 5, 13, 12, 0, 0, 0, time.UTC)
|
||||
parent := func(id string) *string { return &id }
|
||||
tenants := []domain.Tenant{
|
||||
{ID: "group-hanmac-family", Type: domain.TenantTypeCompanyGroup, Name: "한맥가족", Slug: "hanmac-family", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "company-hanmac", Type: domain.TenantTypeCompany, ParentID: parent("group-hanmac-family"), Name: "한맥기술", Slug: "hanmac", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "dept-platform", Type: domain.TenantTypeUserGroup, ParentID: parent("company-hanmac"), Name: "플랫폼실", Slug: "platform", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
{ID: "company-other", Type: domain.TenantTypeCompany, ParentID: parent("group-hanmac-family"), Name: "다른회사", Slug: "other", Status: domain.TenantStatusActive, CreatedAt: now, UpdatedAt: now},
|
||||
}
|
||||
mockSvc.On("ListTenants", mock.Anything, 10000, 0, "").Return(tenants, int64(len(tenants)), nil)
|
||||
mockUsers.On("FindByTenantIDs", mock.Anything, []string{"company-hanmac", "dept-platform"}).Return([]domain.User{}, nil)
|
||||
mockUsers.On("FindByCompanyCodes", mock.Anything, []string{"hanmac", "platform"}).Return([]domain.User{}, nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/org-context?tenantSlug=hanmac", nil)
|
||||
resp, err := app.Test(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var got map[string]any
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&got))
|
||||
scope := got["scope"].(map[string]any)
|
||||
require.Equal(t, "company-hanmac", scope["tenantId"])
|
||||
require.Equal(t, "hanmac", scope["tenantSlug"])
|
||||
|
||||
require.Contains(t, toJSONString(t, got), "dept-platform")
|
||||
require.NotContains(t, toJSONString(t, got), "company-other")
|
||||
}
|
||||
|
||||
func TestTenantHandler_GetOrgContextJSONRequiresApiKey(t *testing.T) {
|
||||
app := fiber.New()
|
||||
h := &TenantHandler{}
|
||||
app.Get("/org-context", h.GetOrgContext)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/org-context", nil)
|
||||
resp, err := app.Test(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestTenantHandler_ListTenantsReturnsServiceUnavailableWhenProjectionStatusFails(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockSvc := new(MockTenantService)
|
||||
@@ -518,6 +641,62 @@ func TestTenantHandler_ExportTenantsCSV_OmitsIDsAndUsesParentSlug(t *testing.T)
|
||||
mockSvc.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestTenantHandler_ExportTenantsCSV_FiltersDescendantsByParentIDWithIDs(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockSvc := new(MockTenantService)
|
||||
h := &TenantHandler{Service: mockSvc}
|
||||
|
||||
app.Get("/tenants/export", h.ExportTenantsCSV)
|
||||
|
||||
parentID := "11111111-2222-4333-8444-555555555555"
|
||||
childID := "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"
|
||||
grandchildID := "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff"
|
||||
unrelatedID := "cccccccc-dddd-4eee-8fff-111111111111"
|
||||
tenants := []domain.Tenant{
|
||||
{
|
||||
ID: parentID,
|
||||
Name: "Parent Org",
|
||||
Type: domain.TenantTypeCompany,
|
||||
Slug: "parent-org",
|
||||
},
|
||||
{
|
||||
ID: childID,
|
||||
Name: "Child Org",
|
||||
Type: domain.TenantTypeOrganization,
|
||||
ParentID: &parentID,
|
||||
Slug: "child-org",
|
||||
},
|
||||
{
|
||||
ID: grandchildID,
|
||||
Name: "Leaf Team",
|
||||
Type: domain.TenantTypeUserGroup,
|
||||
ParentID: &childID,
|
||||
Slug: "leaf-team",
|
||||
},
|
||||
{
|
||||
ID: unrelatedID,
|
||||
Name: "Unrelated Org",
|
||||
Type: domain.TenantTypeOrganization,
|
||||
Slug: "unrelated-org",
|
||||
},
|
||||
}
|
||||
|
||||
mockSvc.On("ListTenants", mock.Anything, 10000, 0, "").Return(tenants, int64(len(tenants)), nil)
|
||||
|
||||
req := httptest.NewRequest("GET", "/tenants/export?includeIds=true&parentId="+parentID, nil)
|
||||
resp, _ := app.Test(req)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
text := string(body)
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
assert.Contains(t, text, "tenant_id,name,type,parent_tenant_id,parent_tenant_slug,slug,memo,email_domain,visibility,org_unit_type")
|
||||
assert.Contains(t, text, childID+",Child Org,ORGANIZATION,"+parentID+",parent-org,child-org,")
|
||||
assert.Contains(t, text, grandchildID+",Leaf Team,USER_GROUP,"+childID+",child-org,leaf-team,")
|
||||
assert.NotContains(t, text, unrelatedID)
|
||||
assert.NotContains(t, text, "Parent Org")
|
||||
mockSvc.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestTenantHandler_ImportTenantsCSVCreatesTenant(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockSvc := new(MockTenantService)
|
||||
|
||||
Reference in New Issue
Block a user