kra-new/internal/modules/system/data/repository/menu_test.go

185 lines
6.7 KiB
Go

package system
import (
"context"
"testing"
"time"
"kra/internal/conf"
"kra/internal/modules/system/biz"
)
func newMenuTestData(t *testing.T) *Data {
t.Helper()
db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
if err != nil {
t.Fatal(err)
}
if err = db.AutoMigrate(&menuPO{}, &menuParameterPO{}, &menuButtonPO{}, &authorityButtonPO{}, &authorityPO{}, &authorityMenuPO{}); err != nil {
t.Fatal(err)
}
data := &Data{
gormDB: newReloadableDB(db, nil),
runtime: conf.NewRuntime(&conf.Data{Database: &conf.Data_Database{Driver: "sqlite"}}, &conf.AdminBackend{}),
}
t.Cleanup(func() { data.gormDB.close() })
return data
}
func TestMenuCreatePreservesSubmittedTimestamps(t *testing.T) {
data := newMenuTestData(t)
ctx := context.Background()
createdAt := time.Date(2025, time.January, 2, 3, 4, 5, 0, time.UTC)
updatedAt := time.Date(2025, time.February, 3, 4, 5, 6, 0, time.UTC)
menu := &biz.Menu{CreatedAt: createdAt, UpdatedAt: updatedAt, Name: "created", Path: "created", Component: "view/created.vue", Title: "Created"}
if err := (&menuRepo{data: data}).Create(ctx, menu); err != nil {
t.Fatal(err)
}
var stored menuPO
if err := data.gormDB.WithContext(ctx).First(&stored, menu.ID).Error; err != nil {
t.Fatal(err)
}
if !stored.CreatedAt.Equal(createdAt) || !stored.UpdatedAt.Equal(updatedAt) {
t.Fatalf("stored timestamps = (%v, %v), want (%v, %v)", stored.CreatedAt, stored.UpdatedAt, createdAt, updatedAt)
}
}
func TestSetAuthorityMenusRejectsMissingAuthority(t *testing.T) {
data := newMenuTestData(t)
err := (&menuRepo{data: data}).SetAuthorityMenus(context.Background(), 999, nil)
if err == nil {
t.Fatal("SetAuthorityMenus missing authority succeeded")
}
}
func TestSetMenuRolesPreservesDuplicateAuthorityIDs(t *testing.T) {
data := newMenuTestData(t)
ctx := context.Background()
if err := (&menuRepo{data: data}).SetMenuRoles(ctx, 10, []uint{888, 888}); err != nil {
t.Fatal(err)
}
var count int64
if err := data.gormDB.WithContext(ctx).Model(&authorityMenuPO{}).
Where("sys_base_menu_id = ? AND sys_authority_authority_id = ?", 10, 888).
Count(&count).Error; err != nil {
t.Fatal(err)
}
if count != 2 {
t.Fatalf("authority-menu rows = %d, want duplicate role IDs preserved", count)
}
}
func TestMenuUpdateRebuildsRelationsWithoutChangingRequestedIdentity(t *testing.T) {
data := newMenuTestData(t)
ctx := context.Background()
createdAt := time.Date(2025, time.March, 4, 5, 6, 7, 0, time.UTC)
updatedAt := time.Date(2025, time.April, 5, 6, 7, 8, 0, time.UTC)
if err := data.gormDB.WithContext(ctx).Create(&menuPO{ID: 10, Name: "before", Path: "before", Component: "view/before.vue", Title: "Before"}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&menuParameterPO{ID: 21, CreatedAt: createdAt, UpdatedAt: updatedAt, MenuID: 10, Type: "query", Key: "old", Value: "old"}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&menuButtonPO{ID: 31, CreatedAt: createdAt, UpdatedAt: updatedAt, MenuID: 10, Name: "edit", Description: "old"}).Error; err != nil {
t.Fatal(err)
}
if err := data.gormDB.WithContext(ctx).Create(&authorityButtonPO{AuthorityID: 888, MenuID: 10, ButtonID: 31}).Error; err != nil {
t.Fatal(err)
}
repo := &menuRepo{data: data}
err := repo.Update(ctx, &biz.Menu{
ID: 10,
Name: "after",
Path: "after",
Component: "view/after.vue",
Title: "After",
Parameters: []*biz.MenuParameter{{
ID: 21, CreatedAt: createdAt, UpdatedAt: updatedAt, Type: "params", Key: "new", Value: "value",
}},
Buttons: []*biz.MenuButton{{
ID: 31, CreatedAt: createdAt, UpdatedAt: updatedAt, Name: "edit", Description: "new",
}},
})
if err != nil {
t.Fatal(err)
}
var parameter menuParameterPO
if err = data.gormDB.WithContext(ctx).First(&parameter, 21).Error; err != nil {
t.Fatal(err)
}
if parameter.MenuID != 10 || parameter.Type != "params" || parameter.Key != "new" || parameter.Value != "value" {
t.Fatalf("parameter = %+v", parameter)
}
if !parameter.CreatedAt.Equal(createdAt) || !parameter.UpdatedAt.Equal(updatedAt) {
t.Fatalf("parameter timestamps = (%v, %v), want (%v, %v)", parameter.CreatedAt, parameter.UpdatedAt, createdAt, updatedAt)
}
var button menuButtonPO
if err = data.gormDB.WithContext(ctx).First(&button, 31).Error; err != nil {
t.Fatal(err)
}
if button.MenuID != 10 || button.Name != "edit" || button.Description != "new" {
t.Fatalf("button = %+v", button)
}
if !button.CreatedAt.Equal(createdAt) || !button.UpdatedAt.Equal(updatedAt) {
t.Fatalf("button timestamps = (%v, %v), want (%v, %v)", button.CreatedAt, button.UpdatedAt, createdAt, updatedAt)
}
var links int64
if err = data.gormDB.WithContext(ctx).Model(&authorityButtonPO{}).
Where("authority_id = ? AND sys_menu_id = ? AND sys_base_menu_btn_id = ?", 888, 10, 31).
Count(&links).Error; err != nil {
t.Fatal(err)
}
if links != 1 {
t.Fatalf("authority-button links = %d, want 1", links)
}
}
func TestSetMenuRolesStrictOnlyChangesManagedAuthorities(t *testing.T) {
data := newMenuTestData(t)
enableStrictAuthorityTestMode(data)
db := data.gormDB.WithContext(context.Background())
rootID, actorID, childID, siblingID := uint(888), uint(4001), uint(4002), uint(5001)
if err := db.Create(&[]authorityPO{
{AuthorityID: rootID, ParentID: authorityUintPointer(0)},
{AuthorityID: actorID, ParentID: &rootID},
{AuthorityID: childID, ParentID: &actorID},
{AuthorityID: siblingID, ParentID: &rootID},
}).Error; err != nil {
t.Fatal(err)
}
menu := menuPO{ID: 10, Name: "managed", Path: "managed"}
if err := db.Create(&menu).Error; err != nil {
t.Fatal(err)
}
if err := db.Create(&[]authorityMenuPO{
{SysAuthorityAuthorityID: actorID, SysBaseMenuID: menu.ID},
{SysAuthorityAuthorityID: siblingID, SysBaseMenuID: menu.ID},
}).Error; err != nil {
t.Fatal(err)
}
ctx := biz.NewActorContext(context.Background(), biz.Actor{AuthorityID: actorID})
repo := &menuRepo{data: data}
if err := repo.SetMenuRoles(ctx, menu.ID, []uint{siblingID}); err == nil {
t.Fatal("SetMenuRoles() accepted an out-of-scope authority")
}
if err := repo.SetMenuRoles(ctx, menu.ID, []uint{childID}); err != nil {
t.Fatalf("SetMenuRoles() rejected a managed authority: %v", err)
}
var siblingCount, childCount int64
if err := db.Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ? AND sys_base_menu_id = ?", siblingID, menu.ID).Count(&siblingCount).Error; err != nil {
t.Fatal(err)
}
if err := db.Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ? AND sys_base_menu_id = ?", childID, menu.ID).Count(&childCount).Error; err != nil {
t.Fatal(err)
}
if siblingCount != 1 || childCount != 1 {
t.Fatalf("menu-role counts sibling/child = %d/%d, want 1/1", siblingCount, childCount)
}
}