thread-master/internal/bootstrap/admin_test.go

127 lines
3.6 KiB
Go

package bootstrap
import (
"context"
"testing"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
"haixun-backend/internal/model/member/domain/entity"
domrepo "haixun-backend/internal/model/member/domain/repository"
"golang.org/x/crypto/bcrypt"
)
type memoryMemberRepo struct {
byEmail map[string]*entity.Member
}
func memberKey(tenantID, email string) string {
return tenantID + ":" + normalizeEmail(email)
}
func (m *memoryMemberRepo) EnsureIndexes(context.Context) error { return nil }
func (m *memoryMemberRepo) Create(_ context.Context, member *entity.Member) (*entity.Member, error) {
if m.byEmail == nil {
m.byEmail = map[string]*entity.Member{}
}
key := memberKey(member.TenantID, member.Email)
if _, ok := m.byEmail[key]; ok {
return nil, app.For(code.Member).ResConflict("member already exists")
}
cp := *member
m.byEmail[key] = &cp
return &cp, nil
}
func (m *memoryMemberRepo) FindByUID(_ context.Context, tenantID, uid string) (*entity.Member, error) {
for _, item := range m.byEmail {
if item.TenantID == tenantID && item.UID == uid {
cp := *item
return &cp, nil
}
}
return nil, app.For(code.Member).ResNotFound("member not found")
}
func (m *memoryMemberRepo) FindByEmail(_ context.Context, tenantID, email string) (*entity.Member, error) {
item, ok := m.byEmail[memberKey(tenantID, email)]
if !ok {
return nil, app.For(code.Member).ResNotFound("member not found")
}
cp := *item
return &cp, nil
}
func (m *memoryMemberRepo) UpdateProfile(context.Context, string, string, domrepo.ProfileUpdate) (*entity.Member, error) {
return nil, app.For(code.Member).SysNotImplemented("not implemented")
}
func (m *memoryMemberRepo) SetActiveThreadsAccountID(_ context.Context, tenantID, uid, accountID string) error {
for _, item := range m.byEmail {
if item.TenantID == tenantID && item.UID == uid {
item.ActiveThreadsAccountID = accountID
return nil
}
}
return app.For(code.Member).ResNotFound("member not found")
}
func (m *memoryMemberRepo) SetRoles(_ context.Context, tenantID, uid string, roles []string) error {
for _, item := range m.byEmail {
if item.TenantID == tenantID && item.UID == uid {
item.Roles = append([]string(nil), roles...)
return nil
}
}
return app.For(code.Member).ResNotFound("member not found")
}
func TestEnsureAdminMemberCreatesAdmin(t *testing.T) {
repo := &memoryMemberRepo{byEmail: map[string]*entity.Member{}}
member, created, err := EnsureAdminMember(context.Background(), repo, AdminOptions{
TenantID: "default",
Email: "admin@haixun.local",
Password: "Admin-Pass-1!",
})
if err != nil {
t.Fatalf("EnsureAdminMember: %v", err)
}
if !created {
t.Fatal("expected created=true")
}
if member.Roles[0] != "admin" {
t.Fatalf("roles=%v", member.Roles)
}
if err := bcrypt.CompareHashAndPassword([]byte(member.PasswordHash), []byte("Admin-Pass-1!")); err != nil {
t.Fatalf("password hash mismatch: %v", err)
}
}
func TestEnsureAdminMemberUpgradesExisting(t *testing.T) {
repo := &memoryMemberRepo{byEmail: map[string]*entity.Member{
memberKey("default", "admin@haixun.local"): {
TenantID: "default",
UID: "uid-1",
Email: "admin@haixun.local",
Roles: []string{"user"},
},
}}
_, created, err := EnsureAdminMember(context.Background(), repo, AdminOptions{
TenantID: "default",
Email: "admin@haixun.local",
Password: "Admin-Pass-1!",
})
if err != nil {
t.Fatalf("EnsureAdminMember: %v", err)
}
if created {
t.Fatal("expected created=false")
}
member := repo.byEmail[memberKey("default", "admin@haixun.local")]
if len(member.Roles) != 1 || member.Roles[0] != "admin" {
t.Fatalf("roles=%v", member.Roles)
}
}