1
0
forked from baron/baron-sso

test code 수정

This commit is contained in:
2026-02-23 16:50:26 +09:00
parent 68becb43bc
commit 4dc4e19c27
18 changed files with 187 additions and 90 deletions

View File

@@ -81,7 +81,7 @@ type AuthHandler struct {
SmsService domain.SmsService
EmailService domain.EmailService
RedisService domain.RedisRepository
KratosAdmin *service.KratosAdminService
KratosAdmin service.KratosAdminService
IdpProvider domain.IdentityProvider
AuditRepo domain.AuditRepository
OathkeeperRepo domain.OathkeeperLogRepository
@@ -148,12 +148,12 @@ func checkPollInterval(redis domain.RedisRepository, key string, interval time.D
return false, int(interval.Seconds())
}
func NewAuthHandler(redisService domain.RedisRepository, idpProvider domain.IdentityProvider, auditRepo domain.AuditRepository, oathkeeperRepo domain.OathkeeperLogRepository, tenantService service.TenantService, ketoService service.KetoService, ketoOutboxRepo repository.KetoOutboxRepository, userRepo repository.UserRepository, consentRepo repository.ClientConsentRepository) *AuthHandler {
func NewAuthHandler(redisService domain.RedisRepository, idpProvider domain.IdentityProvider, auditRepo domain.AuditRepository, oathkeeperRepo domain.OathkeeperLogRepository, tenantService service.TenantService, ketoService service.KetoService, ketoOutboxRepo repository.KetoOutboxRepository, userRepo repository.UserRepository, consentRepo repository.ClientConsentRepository, kratos service.KratosAdminService) *AuthHandler {
return &AuthHandler{
SmsService: service.NewSmsService(),
EmailService: service.NewEmailService(),
RedisService: redisService,
KratosAdmin: service.NewKratosAdminService(),
KratosAdmin: kratos,
IdpProvider: idpProvider,
AuditRepo: auditRepo,
OathkeeperRepo: oathkeeperRepo,

View File

@@ -81,6 +81,7 @@ func (m *AsyncMockUserRepo) Create(ctx context.Context, user *domain.User) error
return args.Error(0)
}
func (m *AsyncMockUserRepo) Update(ctx context.Context, user *domain.User) error { return nil }
func (m *AsyncMockUserRepo) Delete(ctx context.Context, id string) error { return nil }
func (m *AsyncMockUserRepo) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
return nil, nil
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// --- Test Helpers ---
@@ -112,12 +113,15 @@ func TestGetConsentRequest_Skip_AutoAccept(t *testing.T) {
AdminURL: "http://hydra.test",
HTTPClient: client,
},
KratosAdmin: &service.KratosAdminService{
AdminURL: "http://kratos.test",
HTTPClient: client,
},
KratosAdmin: new(MockKratosAdminService), // Reusing MockKratosAdminService if defined or use MockKratosAdminServiceShared
ConsentRepo: consentRepo,
}
h.KratosAdmin.(*MockKratosAdminService).On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
ID: "user-123",
Traits: map[string]interface{}{
"email": "user@test.com",
},
}, nil)
app := newConsentTestApp(h)
req := httptest.NewRequest(http.MethodGet, "/api/v1/auth/consent?consent_challenge=challenge-skip", nil)
@@ -172,13 +176,16 @@ func TestAcceptConsentRequest_Normal(t *testing.T) {
AdminURL: "http://hydra.test",
HTTPClient: client,
},
KratosAdmin: &service.KratosAdminService{
AdminURL: "http://kratos.test",
HTTPClient: client,
},
KratosAdmin: new(MockKratosAdminService),
AuditRepo: auditRepo,
ConsentRepo: consentRepo,
}
h.KratosAdmin.(*MockKratosAdminService).On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
ID: "user-123",
Traits: map[string]interface{}{
"email": "user@test.com",
},
}, nil)
app := newConsentTestApp(h)

View File

@@ -106,7 +106,7 @@ func TestListLinkedRps_PriorityAndAggregation(t *testing.T) {
},
AuditRepo: auditRepo,
ConsentRepo: consentRepo,
KratosAdmin: &service.KratosAdminService{},
KratosAdmin: new(MockKratosAdminService),
}
t.Setenv("KRATOS_PUBLIC_URL", "http://kratos.test")

View File

@@ -11,7 +11,6 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
@@ -81,15 +80,36 @@ func (m *MockIdentityProvider) UpdateUserPassword(loginID, newPassword string, r
}
type MockKratosAdminService struct {
// Simple mock for FindIdentityIDByIdentifier
mock.Mock
}
func (m *MockKratosAdminService) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
// Always return a static ID for simplicity in this test
if identifier == "fail" {
return "", errors.New("not found")
args := m.Called(ctx, identifier)
return args.String(0), args.Error(1)
}
func (m *MockKratosAdminService) GetIdentity(ctx context.Context, id string) (*service.KratosIdentity, error) {
args := m.Called(ctx, id)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return "kratos-identity-id", nil
return args.Get(0).(*service.KratosIdentity), args.Error(1)
}
func (m *MockKratosAdminService) ListIdentities(ctx context.Context) ([]service.KratosIdentity, error) {
return nil, nil
}
func (m *MockKratosAdminService) UpdateIdentity(ctx context.Context, identityID string, traits map[string]interface{}, state string) (*service.KratosIdentity, error) {
return nil, nil
}
func (m *MockKratosAdminService) UpdateIdentityPassword(ctx context.Context, identityID, newPassword string) error {
return nil
}
func (m *MockKratosAdminService) DeleteIdentity(ctx context.Context, identityID string) error {
return nil
}
// --- Helper ---
@@ -142,30 +162,17 @@ func TestPasswordLogin_OIDC_Success(t *testing.T) {
}
})
mockKratos := new(MockKratosAdminService)
mockKratos.On("FindIdentityIDByIdentifier", mock.Anything, "user@example.com").Return("kratos-identity-id", nil)
h := &AuthHandler{
IdpProvider: mockIdp,
KratosAdmin: service.NewKratosAdminService(), // We need to mock this better if resolveKratosIdentityIDFromLoginID calls real API
KratosAdmin: mockKratos,
Hydra: &service.HydraAdminService{
AdminURL: "http://hydra.test",
HTTPClient: &http.Client{Transport: mockHydraTransport(hydraHandler)},
},
}
// Inject Mock Kratos (Hack: overwrite the service field if it was an interface, but it's a struct pointer)
// AuthHandler uses *service.KratosAdminService struct pointer.
// KratosAdminService methods are real. We need to mock HTTP client inside KratosAdminService too.
kratosHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Mock FindIdentityIDByIdentifier response
if strings.Contains(r.URL.Path, "/identities") {
json.NewEncoder(w).Encode([]map[string]interface{}{
{"id": "kratos-identity-id"},
})
return
}
http.NotFound(w, r)
})
h.KratosAdmin.HTTPClient = &http.Client{Transport: mockHydraTransport(kratosHandler)}
h.KratosAdmin.AdminURL = "http://kratos.test"
app := newAuthLoginTestApp(h)
@@ -215,21 +222,18 @@ func TestPasswordLogin_OIDC_InactiveClient(t *testing.T) {
http.NotFound(w, r)
})
mockKratos := new(MockKratosAdminService)
mockKratos.On("FindIdentityIDByIdentifier", mock.Anything, "user@example.com").Return("kratos-identity-id", nil)
h := &AuthHandler{
IdpProvider: mockIdp,
KratosAdmin: service.NewKratosAdminService(),
KratosAdmin: mockKratos,
Hydra: &service.HydraAdminService{
AdminURL: "http://hydra.test",
HTTPClient: &http.Client{Transport: mockHydraTransport(hydraHandler)},
},
}
kratosHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]interface{}{{"id": "kratos-identity-id"}})
})
h.KratosAdmin.HTTPClient = &http.Client{Transport: mockHydraTransport(kratosHandler)}
h.KratosAdmin.AdminURL = "http://kratos.test"
app := newAuthLoginTestApp(h)
body, _ := json.Marshal(map[string]string{
@@ -259,18 +263,15 @@ func TestPasswordLogin_NoOIDC_Success(t *testing.T) {
Subject: "kratos-identity-id",
}, nil)
mockKratos := new(MockKratosAdminService)
mockKratos.On("FindIdentityIDByIdentifier", mock.Anything, "user@example.com").Return("kratos-identity-id", nil)
h := &AuthHandler{
IdpProvider: mockIdp,
KratosAdmin: service.NewKratosAdminService(),
KratosAdmin: mockKratos,
Hydra: service.NewHydraAdminService(),
}
kratosHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]interface{}{{"id": "kratos-identity-id"}})
})
h.KratosAdmin.HTTPClient = &http.Client{Transport: mockHydraTransport(kratosHandler)}
h.KratosAdmin.AdminURL = "http://kratos.test"
app := newAuthLoginTestApp(h)
body, _ := json.Marshal(map[string]string{

View File

@@ -20,7 +20,7 @@ type DevHandler struct {
Hydra *service.HydraAdminService
Redis domain.RedisRepository
SecretRepo domain.ClientSecretRepository
KratosAdmin *service.KratosAdminService
KratosAdmin service.KratosAdminService
ConsentRepo repository.ClientConsentRepository
}

View File

@@ -10,10 +10,10 @@ import (
type RelyingPartyHandler struct {
Service service.RelyingPartyService
KratosAdmin *service.KratosAdminService
KratosAdmin service.KratosAdminService
}
func NewRelyingPartyHandler(s service.RelyingPartyService, kratos *service.KratosAdminService) *RelyingPartyHandler {
func NewRelyingPartyHandler(s service.RelyingPartyService, kratos service.KratosAdminService) *RelyingPartyHandler {
return &RelyingPartyHandler{Service: s, KratosAdmin: kratos}
}

View File

@@ -17,10 +17,10 @@ type TenantHandler struct {
Service service.TenantService
Keto service.KetoService
KetoOutbox repository.KetoOutboxRepository
KratosAdmin *service.KratosAdminService
KratosAdmin service.KratosAdminService
}
func NewTenantHandler(db *gorm.DB, svc service.TenantService, keto service.KetoService, outbox repository.KetoOutboxRepository, kratos *service.KratosAdminService) *TenantHandler {
func NewTenantHandler(db *gorm.DB, svc service.TenantService, keto service.KetoService, outbox repository.KetoOutboxRepository, kratos service.KratosAdminService) *TenantHandler {
return &TenantHandler{
DB: db,
Service: svc,

View File

@@ -85,7 +85,7 @@ func TestTenantHandler_CreateTenant(t *testing.T) {
}
body, _ := json.Marshal(input)
mockSvc.On("RegisterTenant", mock.Anything, "Test Tenant", "test-tenant", "", []string{"test.com"}).
mockSvc.On("RegisterTenant", mock.Anything, "Test Tenant", "test-tenant", "", []string{"test.com"}, (*string)(nil)).
Return(&domain.Tenant{ID: "t1", Name: "Test Tenant", Slug: "test-tenant"}, nil)
req := httptest.NewRequest("POST", "/tenants", bytes.NewReader(body))

View File

@@ -20,16 +20,24 @@ type MockUserGroupService struct {
mock.Mock
}
func (m *MockUserGroupService) Create(ctx context.Context, group *domain.UserGroup) error {
return m.Called(ctx, group).Error(0)
func (m *MockUserGroupService) Create(ctx context.Context, tenantID string, parentID *string, name, description, unitType string) (*domain.UserGroup, error) {
args := m.Called(ctx, tenantID, parentID, name, description, unitType)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*domain.UserGroup), args.Error(1)
}
func (m *MockUserGroupService) Update(ctx context.Context, group *domain.UserGroup) error {
return m.Called(ctx, group).Error(0)
func (m *MockUserGroupService) Update(ctx context.Context, tenantID, groupID string, name, description, unitType string, parentID *string) (*domain.UserGroup, error) {
args := m.Called(ctx, tenantID, groupID, name, description, unitType, parentID)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*domain.UserGroup), args.Error(1)
}
func (m *MockUserGroupService) Delete(ctx context.Context, id string) error {
return m.Called(ctx, id).Error(0)
func (m *MockUserGroupService) Delete(ctx context.Context, tenantID, groupID string) error {
return m.Called(ctx, tenantID, groupID).Error(0)
}
func (m *MockUserGroupService) Get(ctx context.Context, id string) (*domain.UserGroup, error) {
@@ -95,9 +103,7 @@ func TestUserGroupHandler_Create(t *testing.T) {
app.Post("/tenants/:tenantId/user-groups", h.Create)
body, _ := json.Marshal(map[string]string{"name": "New Group"})
mockSvc.On("Create", mock.Anything, mock.MatchedBy(func(g *domain.UserGroup) bool {
return g.Name == "New Group" && g.TenantID == "t1"
})).Return(nil)
mockSvc.On("Create", mock.Anything, "t1", mock.Anything, "New Group", mock.Anything, mock.Anything).Return(&domain.UserGroup{ID: "g1", Name: "New Group"}, nil)
req := httptest.NewRequest("POST", "/tenants/t1/user-groups", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")

View File

@@ -14,7 +14,7 @@ import (
)
type UserHandler struct {
KratosAdmin *service.KratosAdminService
KratosAdmin service.KratosAdminService
OryProvider *service.OryProvider
TenantService service.TenantService
KetoService service.KetoService
@@ -22,7 +22,7 @@ type UserHandler struct {
UserRepo repository.UserRepository
}
func NewUserHandler(kratosAdmin *service.KratosAdminService, oryProvider *service.OryProvider, tenantService service.TenantService, ketoService service.KetoService, ketoOutboxRepo repository.KetoOutboxRepository, userRepo repository.UserRepository) *UserHandler {
func NewUserHandler(kratosAdmin service.KratosAdminService, oryProvider *service.OryProvider, tenantService service.TenantService, ketoService service.KetoService, ketoOutboxRepo repository.KetoOutboxRepository, userRepo repository.UserRepository) *UserHandler {
return &UserHandler{
KratosAdmin: kratosAdmin,
OryProvider: oryProvider,

View File

@@ -1,8 +1,8 @@
package handler
import (
"baron-sso-backend/internal/domain"
"baron-sso-backend/internal/service"
"bytes"
"context"
"encoding/json"
"net/http/httptest"
@@ -32,13 +32,29 @@ func (m *MockKratosAdminForUser) ListIdentities(ctx context.Context) ([]service.
return args.Get(0).([]service.KratosIdentity), args.Error(1)
}
// Note: In reality, KratosAdminService might not be an interface.
// If it's a struct, we'd need to mock the underlying client or use an interface.
// For the sake of this test, let's assume we can mock it or use a wrapper.
func (m *MockKratosAdminForUser) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
return "", nil
}
func (m *MockKratosAdminForUser) UpdateIdentity(ctx context.Context, identityID string, traits map[string]interface{}, state string) (*service.KratosIdentity, error) {
return nil, nil
}
func (m *MockKratosAdminForUser) UpdateIdentityPassword(ctx context.Context, identityID, newPassword string) error {
return nil
}
func (m *MockKratosAdminForUser) DeleteIdentity(ctx context.Context, identityID string) error {
return nil
}
func TestUserHandler_CreateUser_InvalidEmail(t *testing.T) {
app := fiber.New()
h := &UserHandler{}
mockKratos := new(MockKratosAdminForUser)
h := &UserHandler{
KratosAdmin: mockKratos,
OryProvider: &service.OryProvider{}, // Assuming it's a struct and non-nil is enough for this check
}
app.Post("/users", h.CreateUser)
payload := map[string]string{
@@ -54,8 +70,8 @@ func TestUserHandler_CreateUser_InvalidEmail(t *testing.T) {
}
func TestUserHandler_GetUser_Forbidden(t *testing.T) {
app := fiber.New()
mockKratos := new(MockKratosAdminForUser)
// app := fiber.New()
// mockKratos := new(MockKratosAdminForUser)
// We need a way to inject mockKratos into UserHandler.
// Since UserHandler uses *service.KratosAdminService (struct),
// we'd typically use an interface here.