kra-oa/app/system/internal/data/data_scope_test.go

107 lines
3.2 KiB
Go

package data
import (
"context"
"errors"
"testing"
"kra/app/system/internal/biz"
"gorm.io/gorm"
)
type dataScopeRecord struct {
ID uint `gorm:"primaryKey"`
DeptID uint
CreatedBy uint
Name string
}
func (dataScopeRecord) TableName() string { return "business_scope_records" }
func newDataScopeTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&dataScopeRecord{}); err != nil {
t.Fatal(err)
}
registerDataScopeCallbacks(db, nil)
sqlDB, err := db.DB()
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = sqlDB.Close() })
return db
}
func TestDataScopeCallbacksFailClosedAndAllowExplicitSystemBypass(t *testing.T) {
db := newDataScopeTestDB(t)
seed := []dataScopeRecord{
{DeptID: 10, CreatedBy: 7, Name: "visible"},
{DeptID: 20, CreatedBy: 8, Name: "hidden"},
{DeptID: 0, CreatedBy: 9, Name: "unassigned"},
}
if err := db.Set("data_scope:skip", true).Create(&seed).Error; err != nil {
t.Fatal(err)
}
var rows []dataScopeRecord
if err := db.WithContext(context.Background()).Find(&rows).Error; !errors.Is(err, errDataScopeRequired) {
t.Fatalf("query without data scope error = %v", err)
}
invalidCtx := biz.NewDataScopeContext(context.Background(), biz.DataScope{UserID: 7, AuthorityID: 1, Scope: 1, All: false})
if err := db.WithContext(invalidCtx).Find(&rows).Error; !errors.Is(err, errInvalidDataScope) {
t.Fatalf("query with invalid data scope error = %v", err)
}
scopedCtx := biz.NewDataScopeContext(context.Background(), biz.DataScope{UserID: 7, AuthorityID: 1, Scope: 3, DepartmentIDs: []uint{10}})
rows = nil
if err := db.WithContext(scopedCtx).Order("id").Find(&rows).Error; err != nil {
t.Fatal(err)
}
if len(rows) != 1 || rows[0].Name != "visible" {
t.Fatalf("scoped query rows = %+v", rows)
}
emptyCtx := biz.NewDataScopeContext(context.Background(), biz.DataScope{UserID: 7, AuthorityID: 1, Scope: 5})
rows = nil
if err := db.WithContext(emptyCtx).Find(&rows).Error; err != nil {
t.Fatal(err)
}
if len(rows) != 0 {
t.Fatalf("empty custom scope exposed rows: %+v", rows)
}
rows = nil
if err := db.Set("data_scope:skip", true).Order("id").Find(&rows).Error; err != nil {
t.Fatal(err)
}
if len(rows) != len(seed) {
t.Fatalf("explicit system bypass rows = %d, want %d", len(rows), len(seed))
}
}
func TestDataScopeCreateRequiresIdentityAndStampsOwnership(t *testing.T) {
db := newDataScopeTestDB(t)
if err := db.Create(&dataScopeRecord{Name: "missing"}).Error; !errors.Is(err, errDataScopeRequired) {
t.Fatalf("create without data scope error = %v", err)
}
ctx := biz.NewDataScopeContext(context.Background(), biz.DataScope{UserID: 7, AuthorityID: 1, Scope: 3, PrimaryDeptID: 10, DepartmentIDs: []uint{10}})
created := dataScopeRecord{Name: "owned", DeptID: 999, CreatedBy: 999}
if err := db.WithContext(ctx).Create(&created).Error; err != nil {
t.Fatal(err)
}
var stored dataScopeRecord
if err := db.Set("data_scope:skip", true).First(&stored, created.ID).Error; err != nil {
t.Fatal(err)
}
if stored.DeptID != 10 || stored.CreatedBy != 7 {
t.Fatalf("stamped ownership = dept:%d user:%d, want 10/7", stored.DeptID, stored.CreatedBy)
}
}