첫 커밋: 로컬 프로젝트 업로드
This commit is contained in:
157
baron-sso/backend/internal/bootstrap/admin_account_test.go
Normal file
157
baron-sso/backend/internal/bootstrap/admin_account_test.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnsureSuperAdminCreatesIdentityLocalUserAndKetoRelation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
identityAdmin := &fakeSuperAdminIdentityAdmin{createdID: "identity-1"}
|
||||
store := &fakeSuperAdminStore{}
|
||||
|
||||
result, err := EnsureSuperAdmin(ctx, identityAdmin, store, EnsureSuperAdminOptions{
|
||||
Email: "new-admin@example.com",
|
||||
Password: "Password!123",
|
||||
Name: "New Admin",
|
||||
Source: "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("EnsureSuperAdmin returned error: %v", err)
|
||||
}
|
||||
if !result.IdentityCreated {
|
||||
t.Fatal("identity must be created")
|
||||
}
|
||||
if !result.LocalUserCreated {
|
||||
t.Fatal("local user must be created")
|
||||
}
|
||||
if result.IdentityID != "identity-1" {
|
||||
t.Fatalf("identity ID = %q, want identity-1", result.IdentityID)
|
||||
}
|
||||
if store.user == nil {
|
||||
t.Fatal("local user was not stored")
|
||||
}
|
||||
if store.user.Email != "new-admin@example.com" {
|
||||
t.Fatalf("local user email = %q", store.user.Email)
|
||||
}
|
||||
if store.user.Role != domain.RoleSuperAdmin {
|
||||
t.Fatalf("local user role = %q, want %q", store.user.Role, domain.RoleSuperAdmin)
|
||||
}
|
||||
if len(store.ketoSubjects) != 1 || store.ketoSubjects[0] != "User:identity-1" {
|
||||
t.Fatalf("keto subjects = %#v, want User:identity-1", store.ketoSubjects)
|
||||
}
|
||||
if identityAdmin.createdUser == nil || identityAdmin.createdUser.Attributes["role"] != domain.RoleSuperAdmin {
|
||||
t.Fatalf("created identity attributes = %#v", identityAdmin.createdUser)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureSuperAdminPromotesExistingLocalUser(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
identityAdmin := &fakeSuperAdminIdentityAdmin{existingID: "identity-1"}
|
||||
store := &fakeSuperAdminStore{
|
||||
user: &domain.User{
|
||||
ID: "local-user-1",
|
||||
Email: "existing@example.com",
|
||||
Name: "Existing",
|
||||
Role: domain.RoleUser,
|
||||
Status: domain.UserStatusPreboarding,
|
||||
},
|
||||
}
|
||||
|
||||
result, err := EnsureSuperAdmin(ctx, identityAdmin, store, EnsureSuperAdminOptions{
|
||||
Email: "existing@example.com",
|
||||
Password: "Password!123",
|
||||
Name: "Existing Admin",
|
||||
Source: "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("EnsureSuperAdmin returned error: %v", err)
|
||||
}
|
||||
if result.IdentityCreated {
|
||||
t.Fatal("existing identity must not be recreated")
|
||||
}
|
||||
if !result.LocalUserUpdated {
|
||||
t.Fatal("local user must be promoted")
|
||||
}
|
||||
if store.user.Role != domain.RoleSuperAdmin {
|
||||
t.Fatalf("local user role = %q, want %q", store.user.Role, domain.RoleSuperAdmin)
|
||||
}
|
||||
if store.user.Status != domain.UserStatusActive {
|
||||
t.Fatalf("local user status = %q, want %q", store.user.Status, domain.UserStatusActive)
|
||||
}
|
||||
if len(store.ketoSubjects) != 1 || store.ketoSubjects[0] != "User:local-user-1" {
|
||||
t.Fatalf("keto subjects = %#v, want User:local-user-1", store.ketoSubjects)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureSuperAdminRequiresPasswordForNewIdentity(t *testing.T) {
|
||||
_, err := EnsureSuperAdmin(context.Background(), &fakeSuperAdminIdentityAdmin{}, &fakeSuperAdminStore{}, EnsureSuperAdminOptions{
|
||||
Email: "new-admin@example.com",
|
||||
Name: "New Admin",
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeSuperAdminIdentityAdmin struct {
|
||||
existingID string
|
||||
createdID string
|
||||
createdUser *domain.BrokerUser
|
||||
createdSecret string
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminIdentityAdmin) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
|
||||
return f.existingID, nil
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminIdentityAdmin) CreateUser(ctx context.Context, user *domain.BrokerUser, password string) (string, error) {
|
||||
if f.createdID == "" {
|
||||
return "", errors.New("created id is not configured")
|
||||
}
|
||||
f.createdUser = user
|
||||
f.createdSecret = password
|
||||
return f.createdID, nil
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminIdentityAdmin) UpdateIdentityPassword(ctx context.Context, identityID string, newPassword string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeSuperAdminStore struct {
|
||||
user *domain.User
|
||||
ketoSubjects []string
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminStore) FindUserByEmail(ctx context.Context, email string) (*domain.User, error) {
|
||||
if f.user == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return f.user, nil
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminStore) CreateUser(ctx context.Context, user *domain.User) error {
|
||||
copied := *user
|
||||
f.user = &copied
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminStore) UpdateUserSuperAdmin(ctx context.Context, userID string, name string) (*domain.User, error) {
|
||||
if f.user == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
f.user.Role = domain.RoleSuperAdmin
|
||||
f.user.Status = domain.UserStatusActive
|
||||
if name != "" {
|
||||
f.user.Name = name
|
||||
}
|
||||
return f.user, nil
|
||||
}
|
||||
|
||||
func (f *fakeSuperAdminStore) EnqueueSuperAdminRelation(ctx context.Context, userID string) error {
|
||||
f.ketoSubjects = append(f.ketoSubjects, "User:"+userID)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user