Files
hfb_sys/backend/internal/modules/distribution/auth_onboard_test.go
T
yml2213andCursor 768902f2f7 feat(distribution): 补齐退款加价回退、本站自卖与开通默认规则
退款时压缩卖方加价,人工/自动批次仅完结单可入账,号主收入进主站钱包;仲裁后重算释放并支持作废未入账 DS。开通时四种模式按默认生效,对外口径合并为 35/40/25,不再单独展示通道费。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 18:13:46 +08:00

179 lines
5.2 KiB
Go

package distribution
import (
"context"
"testing"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/modules/auth"
"golang.org/x/crypto/bcrypt"
)
func TestOnboardSiteAndLoginFlow(t *testing.T) {
db := distributionTestDB(t)
repo := NewRepository(db)
jwtMgr := auth.NewJWTManager("test_secret_32_bytes_long_keys_123")
svc := NewService(repo, jwtMgr)
ctx := context.Background()
// 1. Onboard new site
req := OnboardSiteRequest{
SiteCode: "gz_dist",
SiteName: "广州分销站",
Domain: "gz.distribution.com",
AdminUsername: "gz_operator",
AdminPassword: "Password123!",
AdminNickname: "广州运营小李",
MemberType: "operator",
}
resp, err := svc.OnboardSite(ctx, req)
if err != nil {
t.Fatalf("failed to onboard site: %v", err)
}
if resp.Site.SiteCode != "gz_dist" {
t.Fatalf("expected SiteCode gz_dist, got %s", resp.Site.SiteCode)
}
if resp.Member.Username != "gz_operator" {
t.Fatalf("expected Username gz_operator, got %s", resp.Member.Username)
}
if resp.Member.IsSuperadmin {
t.Fatalf("expected IsSuperadmin=false for site member")
}
if resp.Member.SiteID == nil || *resp.Member.SiteID != resp.Site.ID {
t.Fatalf("expected SiteID=%d, got %v", resp.Site.ID, resp.Member.SiteID)
}
if resp.Rule.DistributorReceiveRatio != 35 || resp.Rule.PlatformSellRatio != 40 || resp.Rule.ServiceFeeValue != 25 {
t.Fatalf("expected default 35/40/25, got %+v", resp.Rule)
}
if resp.Rule.Status != "active" {
t.Fatalf("onboard rules should be active by default, got %s", resp.Rule.Status)
}
// 2. Duplicate site code or domain check
dupReq := req
dupReq.AdminUsername = "gz_operator_2"
if _, err := svc.OnboardSite(ctx, dupReq); err != ErrDuplicateSiteCodeOrDomain {
t.Fatalf("expected ErrDuplicateSiteCodeOrDomain, got %v", err)
}
// Duplicate username check
dupUserReq := req
dupUserReq.SiteCode = "gz_dist_2"
dupUserReq.Domain = "gz2.distribution.com"
if _, err := svc.OnboardSite(ctx, dupUserReq); err != ErrDuplicateUsername {
t.Fatalf("expected ErrDuplicateUsername, got %v", err)
}
// 3. Login with onboarded credentials
loginResp, err := svc.Login(ctx, DistributionLoginRequest{
Username: "gz_operator",
Password: "Password123!",
}, "127.0.0.1")
if err != nil {
t.Fatalf("failed to login: %v", err)
}
if loginResp.Token == "" {
t.Fatalf("expected token, got empty")
}
if loginResp.Member.SiteCode != "gz_dist" {
t.Fatalf("expected site code gz_dist, got %s", loginResp.Member.SiteCode)
}
// 4. Login with wrong password
_, err = svc.Login(ctx, DistributionLoginRequest{
Username: "gz_operator",
Password: "wrong_password",
}, "127.0.0.1")
if err != ErrInvalidCredential {
t.Fatalf("expected ErrInvalidCredential, got %v", err)
}
// 5. Login with non-existent user
_, err = svc.Login(ctx, DistributionLoginRequest{
Username: "non_existent",
Password: "Password123!",
}, "127.0.0.1")
if err != ErrInvalidCredential {
t.Fatalf("expected ErrInvalidCredential, got %v", err)
}
// 6. Test disabled user
if err := db.Model(&model.AdminUser{}).Where("username = ?", "gz_operator").Update("status", "disabled").Error; err != nil {
t.Fatal(err)
}
_, err = svc.Login(ctx, DistributionLoginRequest{
Username: "gz_operator",
Password: "Password123!",
}, "127.0.0.1")
if err != ErrAdminDisabled {
t.Fatalf("expected ErrAdminDisabled, got %v", err)
}
hash, _ := bcrypt.GenerateFromPassword([]byte("SuperAdmin123!"), bcrypt.DefaultCost)
plainAdmin := model.AdminUser{
Username: "plain_admin",
PasswordHash: string(hash),
Nickname: "无角色管理员",
Status: "active",
TokenVersion: 1,
}
if err := db.Create(&plainAdmin).Error; err != nil {
t.Fatal(err)
}
plainLogin, err := svc.Login(ctx, DistributionLoginRequest{
Username: "plain_admin",
Password: "SuperAdmin123!",
}, "127.0.0.1")
if err != nil {
t.Fatalf("plain admin login failed: %v", err)
}
if plainLogin.Member.IsSuperadmin {
t.Fatalf("admin without super_admin role or all_view must not be superadmin")
}
superRole := model.Role{Code: "super_admin", Name: "超级管理员"}
if err := db.Create(&superRole).Error; err != nil {
t.Fatal(err)
}
superAdmin := model.AdminUser{
Username: "platform_admin",
PasswordHash: string(hash),
Nickname: "平台超级管理员",
Status: "active",
TokenVersion: 1,
}
if err := db.Create(&superAdmin).Error; err != nil {
t.Fatal(err)
}
if err := db.Create(&model.AdminUserRole{AdminID: superAdmin.ID, RoleID: superRole.ID}).Error; err != nil {
t.Fatal(err)
}
superLoginResp, err := svc.Login(ctx, DistributionLoginRequest{
Username: "platform_admin",
Password: "SuperAdmin123!",
}, "127.0.0.1")
if err != nil {
t.Fatalf("superadmin login failed: %v", err)
}
if !superLoginResp.Member.IsSuperadmin {
t.Fatalf("expected IsSuperadmin=true for platform superadmin")
}
if superLoginResp.Member.SiteID != nil {
t.Fatalf("expected nil SiteID for superadmin, got %v", superLoginResp.Member.SiteID)
}
// 8. Test Me profile
profile, err := svc.Me(ctx, superAdmin.ID)
if err != nil {
t.Fatalf("failed to get profile: %v", err)
}
if profile.Username != "platform_admin" || !profile.IsSuperadmin {
t.Fatalf("unexpected profile: %#v", profile)
}
}