package bell_minimal_menu_test import ( "os" "reflect" "sort" "testing" "gorm.io/driver/postgres" "gorm.io/gorm" versionlocal "go-admin/cmd/migrate/migration/version-local" ) var expectedVisibleMenus = []string{ "事件查询", "用户管理", "系统管理", "菜单管理", "角色管理", "规则配置", "预警中心", "预警管理", } func TestBellMinimalMenuMigration(t *testing.T) { databaseURL := os.Getenv("BELL_MINIMAL_MENU_TEST_DATABASE_URL") if databaseURL == "" { t.Skip("minimal menu database is not configured") } db, err := gorm.Open(postgres.Open(databaseURL), &gorm.Config{}) if err != nil { t.Fatal(err) } assertVisibleMenus(t, db) assertUnusedMenusRetainedAndHidden(t, db) assertOperatorHasNoDefaultMenus(t, db) var rowCountBefore int64 if err = db.Table("sys_menu").Count(&rowCountBefore).Error; err != nil { t.Fatal(err) } if err = db.Exec(`UPDATE sys_menu SET visible = '0' WHERE title IN ('开发工具','定时任务','系统工具')`).Error; err != nil { t.Fatal(err) } if err = db.Exec(`UPDATE sys_menu SET visible = '1' WHERE title IN ('系统管理','预警中心')`).Error; err != nil { t.Fatal(err) } if err = db.Transaction(versionlocal.ApplyBellMinimalMenuVisibility); err != nil { t.Fatal(err) } if err = db.Transaction(versionlocal.ApplyBellMinimalMenuVisibility); err != nil { t.Fatalf("reapplying minimal menu policy failed: %v", err) } var rowCountAfter int64 if err = db.Table("sys_menu").Count(&rowCountAfter).Error; err != nil { t.Fatal(err) } if rowCountAfter != rowCountBefore { t.Fatalf("menu records changed during visibility migration: before=%d after=%d", rowCountBefore, rowCountAfter) } assertVisibleMenus(t, db) assertUnusedMenusRetainedAndHidden(t, db) } func assertVisibleMenus(t *testing.T, db *gorm.DB) { t.Helper() var titles []string if err := db.Table("sys_menu"). Where("menu_type IN ? AND deleted_at IS NULL AND visible = ?", []string{"M", "C"}, "0"). Order("title").Pluck("title", &titles).Error; err != nil { t.Fatal(err) } sort.Strings(titles) expected := append([]string(nil), expectedVisibleMenus...) sort.Strings(expected) if !reflect.DeepEqual(titles, expected) { t.Fatalf("visible menu mismatch\nwant: %v\n got: %v", expected, titles) } } func assertUnusedMenusRetainedAndHidden(t *testing.T, db *gorm.DB) { t.Helper() for _, title := range []string{"开发工具", "定时任务", "系统工具"} { var values []string if err := db.Table("sys_menu").Where("title = ? AND deleted_at IS NULL", title).Pluck("visible", &values).Error; err != nil { t.Fatal(err) } if len(values) == 0 { t.Fatalf("unused upstream menu %q was deleted", title) } for _, visible := range values { if visible != "1" { t.Fatalf("unused upstream menu %q remains visible=%q", title, visible) } } } } func assertOperatorHasNoDefaultMenus(t *testing.T, db *gorm.DB) { t.Helper() var titles []string err := db.Raw(` SELECT DISTINCT m.title FROM sys_role r JOIN sys_role_menu rm ON rm.role_id = r.role_id JOIN sys_menu m ON m.menu_id = rm.menu_id WHERE r.role_key = 'operator' AND m.menu_type IN ('M', 'C') AND m.deleted_at IS NULL AND (m.path LIKE '/admin%' OR m.permission LIKE 'admin:%') `).Scan(&titles).Error if err != nil { t.Fatal(err) } if len(titles) != 0 { t.Fatalf("operator retains default administration menus: %v", titles) } }