1
0
forked from baron/baron-sso

테넌트 소유자, 관리자 분리

This commit is contained in:
2026-03-03 12:38:27 +09:00
parent 7bb1f3f702
commit 86ef9c6f60
23 changed files with 1091 additions and 516 deletions

View File

@@ -162,13 +162,54 @@ func TestTenantService_RegisterTenant_AutoVerify(t *testing.T) {
mockRepo.On("AddDomain", ctx, mock.Anything, "example.com", true).Return(nil)
mockRepo.On("FindBySlug", ctx, slug).Return(&domain.Tenant{ID: "t1", Slug: slug}, nil).Once()
tenant, err := svc.RegisterTenant(ctx, name, slug, domain.TenantTypeCompany, "", domains, nil)
tenant, err := svc.RegisterTenant(ctx, name, slug, domain.TenantTypeCompany, "", domains, nil, "")
assert.NoError(t, err)
assert.NotNil(t, tenant)
assert.Equal(t, "t1", tenant.ID)
mockRepo.AssertExpectations(t)
}
func TestTenantService_RegisterTenant_WithCreator(t *testing.T) {
mockRepo := new(MockTenantRepoForSvc)
mockOutbox := new(MockKetoOutboxRepositoryShared)
svc := NewTenantService(mockRepo, nil, mockOutbox)
ctx := context.Background()
name := "Creator Tenant"
slug := "creator-tenant"
creatorID := "creator-uuid"
tenantID := "t-new"
mockRepo.On("FindBySlug", ctx, slug).Return(nil, nil).Once()
mockRepo.On("Create", ctx, mock.MatchedBy(func(t *domain.Tenant) bool {
return t.Slug == slug
})).Run(func(args mock.Arguments) {
t := args.Get(1).(*domain.Tenant)
t.ID = tenantID
}).Return(nil)
// Expect owners sync
mockOutbox.On("Create", ctx, mock.MatchedBy(func(e *domain.KetoOutbox) bool {
return e.Namespace == "Tenant" && e.Object == tenantID && e.Relation == "owners" && e.Subject == "User:"+creatorID
})).Return(nil)
// Expect admins sync
mockOutbox.On("Create", ctx, mock.MatchedBy(func(e *domain.KetoOutbox) bool {
return e.Namespace == "Tenant" && e.Object == tenantID && e.Relation == "admins" && e.Subject == "User:"+creatorID
})).Return(nil)
// Expect members sync
mockOutbox.On("Create", ctx, mock.MatchedBy(func(e *domain.KetoOutbox) bool {
return e.Namespace == "Tenant" && e.Object == tenantID && e.Relation == "members" && e.Subject == "User:"+creatorID
})).Return(nil)
mockRepo.On("FindBySlug", ctx, slug).Return(&domain.Tenant{ID: tenantID, Slug: slug}, nil).Once()
tenant, err := svc.RegisterTenant(ctx, name, slug, domain.TenantTypeCompany, "", nil, nil, creatorID)
assert.NoError(t, err)
assert.NotNil(t, tenant)
mockRepo.AssertExpectations(t)
mockOutbox.AssertExpectations(t)
}
func TestTenantService_RequestRegistration_NoVerify(t *testing.T) {
mockRepo := new(MockTenantRepoForSvc)
mockOutbox := new(MockKetoOutboxRepositoryShared)
@@ -215,9 +256,15 @@ func TestTenantService_ApproveTenant_SyncAdmin(t *testing.T) {
mockRepo.On("Update", ctx, mock.Anything).Return(nil)
mockUserRepo.On("FindByEmail", adminEmail).Return(&domain.User{ID: userID, Email: adminEmail}, nil)
// Now using Outbox instead of direct Keto call
mockOutbox.On("Create", ctx, mock.MatchedBy(func(e *domain.KetoOutbox) bool {
return e.Namespace == "Tenant" && e.Object == tenantID && e.Relation == "owners" && e.Subject == "User:"+userID
})).Return(nil)
mockOutbox.On("Create", ctx, mock.MatchedBy(func(e *domain.KetoOutbox) bool {
return e.Namespace == "Tenant" && e.Object == tenantID && e.Relation == "admins" && e.Subject == "User:"+userID
})).Return(nil)
mockOutbox.On("Create", ctx, mock.MatchedBy(func(e *domain.KetoOutbox) bool {
return e.Namespace == "Tenant" && e.Object == tenantID && e.Relation == "members" && e.Subject == "User:"+userID
})).Return(nil)
err := svc.ApproveTenant(ctx, tenantID)
assert.NoError(t, err)