package business import ( "context" "gorm.io/gorm" "kra/internal/biz/business" "testing" ) func prepareAccounts(t *testing.T) *gorm.DB { t.Helper() db := openTestDB(t) if err := db.AutoMigrate(&accountPO{}); err != nil { t.Fatal(err) } for _, sql := range []string{ "CREATE TABLE sys_user_authority (sys_user_id INTEGER,sys_authority_authority_id INTEGER)", "CREATE TABLE sys_authorities (authority_id INTEGER,authority_name TEXT,deleted_at DATETIME)", "CREATE TABLE sw_kra_id_map (entity TEXT,old_id TEXT,new_id INTEGER)", "CREATE TABLE tab_promote (id INTEGER,source_db TEXT,busier_id INTEGER,promote_level INTEGER,status INTEGER)", "INSERT INTO sys_authorities VALUES (901,'一级商务',NULL),(902,'已改名二级角色',NULL),(903,'三级商务',NULL)", "INSERT INTO sw_kra_id_map VALUES ('role','2087435436573081601',902)", } { if err := db.Exec(sql).Error; err != nil { t.Fatal(err) } } return db } func TestAccountCreateIsAtomicAndPreferencesDefaultOn(t *testing.T) { db := prepareAccounts(t) r := NewAccountRepo(testData{db}) ctx := context.Background() role, err := r.AuthorityForLevel(ctx, 2) if err != nil || role != 902 { t.Fatalf("角色映射不正确: %d %v", role, err) } a := &business.Account{Username: "child", RealName: "子商务", Password: "hash", Level: 2, ParentID: 10, IDPath: "0,10", AuthorityID: role, Status: 3} if err := r.Create(ctx, a); err != nil { t.Fatal(err) } var po accountPO if err := db.First(&po, a.ID).Error; err != nil { t.Fatal(err) } if po.Password != "hash" || po.Enable != 0 || po.BusinessStatus != 3 || po.UUID == "" { t.Fatalf("账号字段丢失: %+v", po) } pref, err := NewUserPreferenceRepo(testData{db}).Find(ctx, a.ID) if err != nil || !pref.IncludeSubPromote || !pref.IDCardDedup { t.Fatalf("默认偏好缺失: %+v %v", pref, err) } duplicate := &business.Account{Username: "child"} if err := r.Create(ctx, duplicate); err != business.ErrAccountExists { t.Fatalf("应拒绝重复账号: %v", err) } if err := db.Exec("DROP TABLE sys_user_authority").Error; err != nil { t.Fatal(err) } failed := &business.Account{Username: "rollback"} if err := r.Create(ctx, failed); err == nil { t.Fatal("角色关联失败后必须回滚") } var count int64 db.Model(&accountPO{}).Where("username = ?", "rollback").Count(&count) if count != 0 { t.Fatal("留下无角色的部分账号") } } func TestAccountListScopesAndCrossPlatformCounts(t *testing.T) { db := prepareAccounts(t) pos := []accountPO{{ID: 12, Username: "parent", Level: 1, IDPath: "0"}, {ID: 13, Username: "child", Level: 2, ParentID: 12, IDPath: "0,12"}, {ID: 14, Username: "grandchild", Level: 3, ParentID: 13, IDPath: "0,12,13"}, {ID: 99, Username: "outsider", Level: 2, IDPath: "0,123"}} if err := db.Create(&pos).Error; err != nil { t.Fatal(err) } for _, sql := range []string{ "INSERT INTO sys_user_bind_platform(user_id,source_db,platform_busier_id,status) VALUES(13,'a',7,'0'),(13,'b',7,'0'),(13,'c',8,'3'),(14,'a',8,'0')", "INSERT INTO tab_promote VALUES(1,'a',7,1,1),(2,'a',7,1,-2),(3,'a',7,2,1),(1,'b',7,1,1),(4,'c',7,1,1),(5,'a',8,1,1)", } { if err := db.Exec(sql).Error; err != nil { t.Fatal(err) } } r := NewAccountRepo(testData{db}) rows, total, err := r.List(context.Background(), business.UserScope{SelfID: 12, DescendantPath: "0,12"}, business.ListFilter(business.AccountFilter{}), business.ListLimit(20)) if err != nil || total != 2 || len(rows) != 2 { t.Fatalf("下级范围错误: %+v %d %v", rows, total, err) } if rows[0].ParentUserName != "parent" || rows[1].ParentUserName != "child" { t.Fatal("上级账号未关联") } counts, err := r.DirectCounts(context.Background(), []uint{13, 14, 99}) if err != nil { t.Fatal(err) } if counts[13].PromoteCount == nil || *counts[13].PromoteCount != 3 || counts[13].BindCount != 2 || counts[14].PromoteCount == nil || *counts[14].PromoteCount != 1 || counts[14].BindCount != 1 || counts[99].PromoteCount == nil || *counts[99].PromoteCount != 0 { t.Fatalf("渠道数或绑定数口径不一致: %+v", counts) } rows, total, err = r.List(context.Background(), business.UserScope{}, business.ListFilter(business.AccountFilter{})) if err != nil || total != 0 || len(rows) != 0 { t.Fatal("空范围不能放行全量") } }