185 lines
6.7 KiB
Go
185 lines
6.7 KiB
Go
package system
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"kra/app/system/internal/biz"
|
|
"kra/app/system/internal/conf"
|
|
)
|
|
|
|
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(¶meter, 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)
|
|
}
|
|
}
|