package data import ( "context" "errors" "testing" "kra/internal/biz" "kra/internal/conf" "gorm.io/gorm" ) func authorityUintPointer(value uint) *uint { return &value } func enableStrictAuthorityTestMode(data *Data) { currentData, _ := data.runtime.Values() data.runtime.Replace(currentData, &conf.AdminBackend{System: &conf.AdminBackend_System{UseStrictAuth: true}}) } func TestCopyAuthorityStrictPolicyValidationMatchesAdministrationContract(t *testing.T) { data := newTransactionTestData(t) enableStrictAuthorityTestMode(data) db := data.gormDB.WithContext(context.Background()) rootID := uint(888) if err := db.Create(&[]authorityPO{ {AuthorityID: rootID, AuthorityName: "root", ParentID: authorityUintPointer(0)}, {AuthorityID: 900, AuthorityName: "source", ParentID: &rootID}, {AuthorityID: 901, AuthorityName: "stale-source", ParentID: &rootID}, }).Error; err != nil { t.Fatal(err) } if err := db.Create(&apiPO{Path: "/registered", Method: "GET"}).Error; err != nil { t.Fatal(err) } if err := db.Create(&[]casbinRulePO{ newPolicyRule(900, "/registered", "GET"), newPolicyRule(901, "/stale", "POST"), // A root role is allowed to grant registered APIs without already // holding the policy, but a stale policy is still not a registered API. newPolicyRule(rootID, "/stale", "POST"), }).Error; err != nil { t.Fatal(err) } repo := &authorityAccessRepo{data: data} ctx := biz.NewActorContext(context.Background(), biz.Actor{AuthorityID: rootID}) created := &biz.Authority{AuthorityID: 910, AuthorityName: "copy", ParentID: &rootID} if err := repo.CopyAuthority(ctx, 900, created); err != nil { t.Fatalf("root copy of a registered API failed: %v", err) } if exists, err := policyExists(db, created.AuthorityID, "/registered", "GET"); err != nil || !exists { t.Fatalf("copied policy exists = %v, err = %v", exists, err) } staleCopy := &biz.Authority{AuthorityID: 911, AuthorityName: "stale-copy", ParentID: &rootID} if err := repo.CopyAuthority(ctx, 901, staleCopy); err == nil || err.Error() != "存在api不在权限列表中" { t.Fatalf("stale API copy error = %v", err) } var count int64 if err := db.Unscoped().Model(&authorityPO{}).Where("authority_id = ?", staleCopy.AuthorityID).Count(&count).Error; err != nil { t.Fatal(err) } if count != 0 { t.Fatalf("failed copy persisted target authority: count=%d", count) } } func TestCopyAuthorityDuplicateIDWinsOverStrictParentValidation(t *testing.T) { data := newTransactionTestData(t) enableStrictAuthorityTestMode(data) db := data.gormDB.WithContext(context.Background()) rootID := uint(888) if err := db.Create(&[]authorityPO{ {AuthorityID: rootID, AuthorityName: "root", ParentID: authorityUintPointer(0)}, {AuthorityID: 920, AuthorityName: "existing", ParentID: &rootID}, }).Error; err != nil { t.Fatal(err) } invalidParent := uint(999999) ctx := biz.NewActorContext(context.Background(), biz.Actor{AuthorityID: rootID}) err := (&authorityAccessRepo{data: data}).CopyAuthority(ctx, 0, &biz.Authority{AuthorityID: 920, AuthorityName: "duplicate", ParentID: &invalidParent}) if err == nil || err.Error() != "存在相同角色id" { t.Fatalf("duplicate copy error = %v", err) } } func TestListAuthoritiesRequiresCurrentAuthorityOutsideStrictMode(t *testing.T) { data := newTransactionTestData(t) ctx := biz.NewActorContext(context.Background(), biz.Actor{AuthorityID: 999999}) if _, err := (&authorityAccessRepo{data: data}).ListAuthorities(ctx); !errors.Is(err, gorm.ErrRecordNotFound) { t.Fatalf("missing current authority error = %v", err) } } func TestDeleteAuthorityIgnoresOrphanedUserAssociation(t *testing.T) { data := newTransactionTestData(t) ctx := context.Background() db := data.gormDB.WithContext(ctx) if err := db.Create(&authorityPO{AuthorityID: 930, AuthorityName: "orphan-links"}).Error; err != nil { t.Fatal(err) } if err := db.Create(&userAuthorityPO{SysUserID: 999999, SysAuthorityAuthorityID: 930}).Error; err != nil { t.Fatal(err) } if err := (&authorityAccessRepo{data: data}).DeleteAuthority(ctx, 930); err != nil { t.Fatalf("delete with orphaned user association: %v", err) } var authority authorityPO if err := db.Unscoped().Where("authority_id = ?", 930).First(&authority).Error; !errors.Is(err, gorm.ErrRecordNotFound) { t.Fatalf("deleted authority lookup error = %v", err) } var links int64 if err := db.Model(&userAuthorityPO{}).Where("sys_authority_authority_id = ?", 930).Count(&links).Error; err != nil { t.Fatal(err) } if links != 0 { t.Fatalf("orphaned user associations were not removed: %d", links) } } func TestSetAuthorityUsersKeepsPrimaryRoleFallbackBehavior(t *testing.T) { data := newTransactionTestData(t) ctx := context.Background() db := data.gormDB.WithContext(ctx) if err := db.Create(&[]authorityPO{{AuthorityID: 940, AuthorityName: "removed"}, {AuthorityID: 941, AuthorityName: "fallback"}}).Error; err != nil { t.Fatal(err) } users := []userPO{ {Username: "with-fallback", Password: "hash", AuthorityID: 940, Enable: 1}, {Username: "without-fallback", Password: "hash", AuthorityID: 940, Enable: 1}, } if err := db.Create(&users).Error; err != nil { t.Fatal(err) } if err := db.Create(&[]userAuthorityPO{ {SysUserID: users[0].ID, SysAuthorityAuthorityID: 940}, {SysUserID: users[0].ID, SysAuthorityAuthorityID: 941}, {SysUserID: users[1].ID, SysAuthorityAuthorityID: 940}, }).Error; err != nil { t.Fatal(err) } if err := (&authorityAccessRepo{data: data}).SetAuthorityUsers(ctx, 940, nil); err != nil { t.Fatal(err) } var persisted []userPO if err := db.Where("id IN ?", []uint{users[0].ID, users[1].ID}).Order("id").Find(&persisted).Error; err != nil { t.Fatal(err) } if len(persisted) != 2 || persisted[0].AuthorityID != 941 || persisted[1].AuthorityID != 940 { t.Fatalf("primary authority fallback = %+v", persisted) } } func TestAuthorityCustomDataScopeUsesCompatibleColumns(t *testing.T) { data := newTransactionTestData(t) ctx := context.Background() repo := &authorityAccessRepo{data: data} if err := repo.SetDataScope(ctx, 950, 5, []uint{7, 7, 8}); err != nil { t.Fatal(err) } ids, err := repo.DataScopeDepartmentIDs(ctx, 950) if err != nil { t.Fatal(err) } if len(ids) != 3 || ids[0] != 7 || ids[1] != 7 || ids[2] != 8 { t.Fatalf("custom department IDs = %v", ids) } if err = repo.SetDataScope(ctx, 950, 3, []uint{9}); err != nil { t.Fatal(err) } ids, err = repo.DataScopeDepartmentIDs(ctx, 950) if err != nil { t.Fatal(err) } if len(ids) != 0 { t.Fatalf("non-custom scope retained departments: %v", ids) } }