forked from baron/baron-sso
동기화 기초구조 마련
This commit is contained in:
@@ -139,6 +139,19 @@ func (m *MockTenantServiceForUser) GetTenant(ctx context.Context, id string) (*d
|
||||
return args.Get(0).(*domain.Tenant), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockTenantServiceForUser) GetTenantByDomain(ctx context.Context, emailDomain string) (*domain.Tenant, error) {
|
||||
for _, call := range m.ExpectedCalls {
|
||||
if call.Method == "GetTenantByDomain" {
|
||||
args := m.Called(ctx, emailDomain)
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
return args.Get(0).(*domain.Tenant), args.Error(1)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockTenantServiceForUser) ListManageableTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
|
||||
args := m.Called(ctx, userID)
|
||||
if args.Get(0) == nil {
|
||||
@@ -432,6 +445,217 @@ func TestUserHandler_BulkCreateUsers(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserHandler_BulkCreateUsers_ResolvesAdditionalAppointment(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockKratos := new(MockKratosAdmin)
|
||||
mockOry := new(MockOryProvider)
|
||||
mockTenant := new(MockTenantServiceForUser)
|
||||
h := &UserHandler{
|
||||
KratosAdmin: mockKratos,
|
||||
OryProvider: mockOry,
|
||||
TenantService: mockTenant,
|
||||
}
|
||||
app.Post("/users/bulk", h.BulkCreateUsers)
|
||||
|
||||
mockTenant.On("GetTenantBySlug", mock.Anything, "test-tenant").Return(&domain.Tenant{
|
||||
ID: "t-primary",
|
||||
Slug: "test-tenant",
|
||||
Name: "Primary Tenant",
|
||||
Config: domain.JSONMap{},
|
||||
}, nil).Once()
|
||||
mockTenant.On("GetTenant", mock.Anything, "t-primary").Return(&domain.Tenant{
|
||||
ID: "t-primary",
|
||||
Slug: "test-tenant",
|
||||
Name: "Primary Tenant",
|
||||
Config: domain.JSONMap{},
|
||||
}, nil)
|
||||
mockTenant.On("GetTenantBySlug", mock.Anything, "second-tenant").Return(&domain.Tenant{
|
||||
ID: "t-second",
|
||||
Slug: "second-tenant",
|
||||
Name: "Second Tenant",
|
||||
Config: domain.JSONMap{},
|
||||
}, nil).Once()
|
||||
mockOry.On("GetPasswordPolicy").Return(&domain.PasswordPolicy{MinLength: 8}, nil)
|
||||
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
|
||||
appointments, ok := user.Attributes["additionalAppointments"].([]any)
|
||||
if !ok || len(appointments) != 1 {
|
||||
return false
|
||||
}
|
||||
appointment, ok := appointments[0].(map[string]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
metadata, _ := appointment["metadata"].(map[string]any)
|
||||
return appointment["tenantId"] == "t-second" &&
|
||||
appointment["tenantSlug"] == "second-tenant" &&
|
||||
appointment["tenantName"] == "Second Tenant" &&
|
||||
appointment["department"] == "센터" &&
|
||||
appointment["grade"] == "수석" &&
|
||||
appointment["jobTitle"] == "Architecture" &&
|
||||
metadata["employee_id"] == "EMP002"
|
||||
}), mock.Anything).Return("u-appointment", nil).Once()
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"users": []map[string]interface{}{
|
||||
{
|
||||
"email": "dual@test.com",
|
||||
"name": "Dual User",
|
||||
"tenantSlug": "test-tenant",
|
||||
"metadata": map[string]interface{}{"employee_id": "EMP001"},
|
||||
"additionalAppointments": []map[string]interface{}{
|
||||
{
|
||||
"tenantSlug": "second-tenant",
|
||||
"department": "센터",
|
||||
"grade": "수석",
|
||||
"jobTitle": "Architecture",
|
||||
"metadata": map[string]interface{}{"employee_id": "EMP002"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/users/bulk", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, _ := app.Test(req)
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
mockTenant.AssertExpectations(t)
|
||||
mockOry.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestUserHandler_BulkCreateUsers_AppendsEmailDomainTenantAtLowestPriority(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockKratos := new(MockKratosAdmin)
|
||||
mockOry := new(MockOryProvider)
|
||||
mockTenant := new(MockTenantServiceForUser)
|
||||
h := &UserHandler{
|
||||
KratosAdmin: mockKratos,
|
||||
OryProvider: mockOry,
|
||||
TenantService: mockTenant,
|
||||
}
|
||||
app.Post("/users/bulk", h.BulkCreateUsers)
|
||||
|
||||
mockTenant.On("GetTenantBySlug", mock.Anything, "gpdtdc").Return(&domain.Tenant{
|
||||
ID: "t-gpdtdc",
|
||||
Slug: "gpdtdc",
|
||||
Name: "GPDTDC",
|
||||
Config: domain.JSONMap{},
|
||||
}, nil).Once()
|
||||
mockTenant.On("GetTenant", mock.Anything, "t-gpdtdc").Return(&domain.Tenant{
|
||||
ID: "t-gpdtdc",
|
||||
Slug: "gpdtdc",
|
||||
Name: "GPDTDC",
|
||||
Config: domain.JSONMap{},
|
||||
}, nil)
|
||||
mockTenant.On("GetTenantByDomain", mock.Anything, "samaneng.com").Return(&domain.Tenant{
|
||||
ID: "t-saman",
|
||||
Slug: "saman",
|
||||
Name: "삼안",
|
||||
Status: domain.TenantStatusActive,
|
||||
Config: domain.JSONMap{},
|
||||
}, nil).Once()
|
||||
mockOry.On("GetPasswordPolicy").Return(&domain.PasswordPolicy{MinLength: 8}, nil)
|
||||
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
|
||||
if user.Attributes["tenant_id"] != "t-gpdtdc" || user.Attributes["companyCode"] != "gpdtdc" {
|
||||
return false
|
||||
}
|
||||
appointments, ok := user.Attributes["additionalAppointments"].([]any)
|
||||
if !ok || len(appointments) != 1 {
|
||||
return false
|
||||
}
|
||||
appointment, ok := appointments[0].(map[string]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return appointment["tenantId"] == "t-saman" &&
|
||||
appointment["tenantSlug"] == "saman" &&
|
||||
appointment["tenantName"] == "삼안" &&
|
||||
appointment["assignmentSource"] == "email_domain" &&
|
||||
appointment["sourceDomain"] == "samaneng.com"
|
||||
}), mock.Anything).Return("u-domain-assigned", nil).Once()
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"users": []map[string]interface{}{
|
||||
{
|
||||
"email": "user@samaneng.com",
|
||||
"name": "Domain User",
|
||||
"tenantSlug": "gpdtdc",
|
||||
},
|
||||
},
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/users/bulk", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, _ := app.Test(req)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var result map[string]interface{}
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
results := result["results"].([]interface{})
|
||||
assert.True(t, results[0].(map[string]interface{})["success"].(bool))
|
||||
mockTenant.AssertExpectations(t)
|
||||
mockOry.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestUserHandler_BulkCreateUsers_UsesEmailDomainTenantAsPrimaryWhenExplicitTenantMissing(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockKratos := new(MockKratosAdmin)
|
||||
mockOry := new(MockOryProvider)
|
||||
mockTenant := new(MockTenantServiceForUser)
|
||||
h := &UserHandler{
|
||||
KratosAdmin: mockKratos,
|
||||
OryProvider: mockOry,
|
||||
TenantService: mockTenant,
|
||||
}
|
||||
app.Post("/users/bulk", h.BulkCreateUsers)
|
||||
|
||||
mockTenant.On("GetTenantByDomain", mock.Anything, "samaneng.com").Return(&domain.Tenant{
|
||||
ID: "t-saman",
|
||||
Slug: "saman",
|
||||
Name: "삼안",
|
||||
Status: domain.TenantStatusActive,
|
||||
Config: domain.JSONMap{},
|
||||
}, nil).Once()
|
||||
mockTenant.On("GetTenant", mock.Anything, "t-saman").Return(&domain.Tenant{
|
||||
ID: "t-saman",
|
||||
Slug: "saman",
|
||||
Name: "삼안",
|
||||
Status: domain.TenantStatusActive,
|
||||
Config: domain.JSONMap{},
|
||||
}, nil)
|
||||
mockOry.On("GetPasswordPolicy").Return(&domain.PasswordPolicy{MinLength: 8}, nil)
|
||||
mockOry.On("CreateUser", mock.MatchedBy(func(user *domain.BrokerUser) bool {
|
||||
return user.Attributes["tenant_id"] == "t-saman" &&
|
||||
user.Attributes["companyCode"] == "saman" &&
|
||||
user.Attributes["additionalAppointments"] == nil
|
||||
}), mock.Anything).Return("u-domain-primary", nil).Once()
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"users": []map[string]interface{}{
|
||||
{
|
||||
"email": "user@samaneng.com",
|
||||
"name": "Domain Primary User",
|
||||
},
|
||||
},
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
req := httptest.NewRequest("POST", "/users/bulk", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, _ := app.Test(req)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var result map[string]interface{}
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
results := result["results"].([]interface{})
|
||||
assert.True(t, results[0].(map[string]interface{})["success"].(bool))
|
||||
mockTenant.AssertExpectations(t)
|
||||
mockOry.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestUserHandler_ListUsersReturnsServiceUnavailableWhenKratosFails(t *testing.T) {
|
||||
app := fiber.New()
|
||||
mockKratos := new(MockKratosAdmin)
|
||||
|
||||
Reference in New Issue
Block a user