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 }