You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

685 lines
18 KiB

package model
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// setupOrgTestDB 创建机构测试数据库(使用MySQL)
func setupOrgTestDB(t *testing.T) *gorm.DB {
t.Helper()
dsn := "root:dev123456@tcp(219.159.132.177:17173)/base?charset=utf8mb4&parseTime=true&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
require.NoError(t, err)
err = db.AutoMigrate(&Organization{}, &UserOrganization{}, &User{}, &Role{}, &Menu{}, &RoleMenu{})
require.NoError(t, err)
// 清理测试数据(仅清理非种子数据,避免影响运行中的后端)
db.Exec("SET FOREIGN_KEY_CHECKS = 0")
db.Exec("TRUNCATE TABLE role_menu")
db.Exec("TRUNCATE TABLE user_organization")
db.Exec("TRUNCATE TABLE organization")
// 不 TRUNCATE user/role/menu 表,因为后端种子数据在其中
// 仅删除测试创建的记录(通过后续测试自行管理)
db.Exec("DELETE FROM role WHERE is_system = 0")
db.Exec("DELETE FROM menu WHERE name LIKE '测试%'")
db.Exec("DELETE FROM user WHERE username LIKE 'test_%'")
db.Exec("SET FOREIGN_KEY_CHECKS = 1")
return db
}
// createTestOrg 创建测试机构
func createTestOrg(t *testing.T, db *gorm.DB) *Organization {
t.Helper()
now := time.Now()
org := &Organization{
Name: "测试机构",
Code: "test_org",
Leader: "张三",
Phone: "13800138000",
Email: "org@example.com",
SortOrder: 1,
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err := db.Create(org).Error
require.NoError(t, err)
return org
}
// ==================== Organization Tests ====================
// TestOrgInsert 测试插入机构
func TestOrgInsert(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
org := &Organization{
Name: "新机构",
Code: "new_org",
Leader: "李四",
Phone: "13900139000",
Email: "new@example.com",
SortOrder: 5,
Status: 1,
}
id, err := OrgInsert(ctx, db, org)
require.NoError(t, err)
assert.Greater(t, id, int64(0))
assert.Equal(t, id, org.Id)
// 验证数据已保存
saved, err := OrgFindOne(ctx, db, id)
require.NoError(t, err)
assert.Equal(t, "新机构", saved.Name)
assert.Equal(t, "new_org", saved.Code)
assert.Equal(t, "李四", saved.Leader)
}
// TestOrgFindOne 测试根据ID查询机构
func TestOrgFindOne(t *testing.T) {
db := setupOrgTestDB(t)
org := createTestOrg(t, db)
ctx := context.Background()
found, err := OrgFindOne(ctx, db, org.Id)
require.NoError(t, err)
require.NotNil(t, found)
assert.Equal(t, org.Id, found.Id)
assert.Equal(t, "测试机构", found.Name)
assert.Equal(t, "test_org", found.Code)
}
// TestOrgFindOne_NotFound 测试查询不存在的机构
func TestOrgFindOne_NotFound(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
found, err := OrgFindOne(ctx, db, 99999)
require.Error(t, err)
require.Nil(t, found)
assert.Equal(t, ErrNotFound, err)
}
// TestOrgFindOneByCode 测试根据编码查询机构
func TestOrgFindOneByCode(t *testing.T) {
db := setupOrgTestDB(t)
org := createTestOrg(t, db)
ctx := context.Background()
found, err := OrgFindOneByCode(ctx, db, "test_org")
require.NoError(t, err)
require.NotNil(t, found)
assert.Equal(t, org.Id, found.Id)
assert.Equal(t, "测试机构", found.Name)
}
// TestOrgFindAll 测试查询所有启用的机构
func TestOrgFindAll(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
// 创建3个机构:2个启用,1个禁用
now := time.Now()
orgs := []Organization{
{Name: "机构A", Code: "org_a", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now},
{Name: "机构B", Code: "org_b", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now},
{Name: "机构C", Code: "org_c", SortOrder: 3, Status: 1, CreatedAt: now, UpdatedAt: now},
}
for i := range orgs {
err := db.Create(&orgs[i]).Error
require.NoError(t, err)
}
// 将机构C设为禁用(status=0是零值,GORM Create时会使用default:1,需要单独更新)
db.Model(&orgs[2]).Update("status", 0)
// 查询所有启用的机构
result, err := OrgFindAll(ctx, db)
require.NoError(t, err)
assert.Len(t, result, 2)
// 验证按 sort_order 排序
assert.Equal(t, "机构B", result[0].Name) // sort_order=1
assert.Equal(t, "机构A", result[1].Name) // sort_order=2
}
// TestOrgUpdate 测试更新机构
func TestOrgUpdate(t *testing.T) {
db := setupOrgTestDB(t)
org := createTestOrg(t, db)
ctx := context.Background()
// 修改机构数据
org.Name = "更新后的机构"
org.Leader = "王五"
err := OrgUpdate(ctx, db, org)
require.NoError(t, err)
// 验证更新结果
updated, err := OrgFindOne(ctx, db, org.Id)
require.NoError(t, err)
assert.Equal(t, "更新后的机构", updated.Name)
assert.Equal(t, "王五", updated.Leader)
}
// TestOrgDelete 测试删除机构
func TestOrgDelete(t *testing.T) {
db := setupOrgTestDB(t)
org := createTestOrg(t, db)
orgId := org.Id
ctx := context.Background()
err := OrgDelete(ctx, db, orgId)
require.NoError(t, err)
// 验证机构已被删除
_, err = OrgFindOne(ctx, db, orgId)
require.Error(t, err)
assert.Equal(t, ErrNotFound, err)
}
// TestOrgHasChildren 测试检查是否有子机构
func TestOrgHasChildren(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建父机构
parent := &Organization{
Name: "父机构",
Code: "parent_org",
SortOrder: 1,
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err := db.Create(parent).Error
require.NoError(t, err)
// 创建子机构
child := &Organization{
ParentId: parent.Id,
Name: "子机构",
Code: "child_org",
SortOrder: 1,
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err = db.Create(child).Error
require.NoError(t, err)
// 创建无子机构的孤立机构
orphan := &Organization{
Name: "孤立机构",
Code: "orphan_org",
SortOrder: 1,
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err = db.Create(orphan).Error
require.NoError(t, err)
// 验证父机构有子机构
hasChildren, err := OrgHasChildren(ctx, db, parent.Id)
require.NoError(t, err)
assert.True(t, hasChildren)
// 验证孤立机构没有子机构
hasChildren, err = OrgHasChildren(ctx, db, orphan.Id)
require.NoError(t, err)
assert.False(t, hasChildren)
}
// ==================== UserOrganization Tests ====================
// TestUserOrgInsert 测试插入用户-机构关联
func TestUserOrgInsert(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建测试用户
user := &User{
Username: "testuser",
Email: "test@example.com",
Password: "encryptedpassword",
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err := db.Create(user).Error
require.NoError(t, err)
// 创建测试机构
org := createTestOrg(t, db)
// 创建测试角色
role := &Role{
Name: "测试角色",
Code: "test_role",
SortOrder: 1,
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err = db.Create(role).Error
require.NoError(t, err)
// 插入用户-机构关联
uo := &UserOrganization{
UserId: user.Id,
OrgId: org.Id,
RoleId: role.Id,
}
id, err := UserOrgInsert(ctx, db, uo)
require.NoError(t, err)
assert.Greater(t, id, int64(0))
assert.Equal(t, id, uo.Id)
// 验证数据已保存
saved, err := UserOrgFindOne(ctx, db, user.Id, org.Id)
require.NoError(t, err)
assert.Equal(t, user.Id, saved.UserId)
assert.Equal(t, org.Id, saved.OrgId)
assert.Equal(t, role.Id, saved.RoleId)
}
// TestUserOrgFindByUserId 测试根据用户ID查询关联
func TestUserOrgFindByUserId(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建测试用户
user := &User{
Username: "testuser",
Email: "test@example.com",
Password: "encryptedpassword",
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err := db.Create(user).Error
require.NoError(t, err)
// 创建2个机构
org1 := &Organization{Name: "机构1", Code: "org_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
org2 := &Organization{Name: "机构2", Code: "org_2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(org1).Error
require.NoError(t, err)
err = db.Create(org2).Error
require.NoError(t, err)
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(role).Error
require.NoError(t, err)
// 创建2条用户-机构关联
uo1 := &UserOrganization{UserId: user.Id, OrgId: org1.Id, RoleId: role.Id}
uo2 := &UserOrganization{UserId: user.Id, OrgId: org2.Id, RoleId: role.Id}
_, err = UserOrgInsert(ctx, db, uo1)
require.NoError(t, err)
_, err = UserOrgInsert(ctx, db, uo2)
require.NoError(t, err)
// 查询用户的所有机构关联
list, err := UserOrgFindByUserId(ctx, db, user.Id)
require.NoError(t, err)
assert.Len(t, list, 2)
}
// TestUserOrgFindByOrgId 测试根据机构ID查询关联
func TestUserOrgFindByOrgId(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建机构
org := createTestOrg(t, db)
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(role).Error
require.NoError(t, err)
// 创建2个用户
user1 := &User{Username: "user1", Email: "user1@example.com", Password: "pass", Status: 1, CreatedAt: now, UpdatedAt: now}
user2 := &User{Username: "user2", Email: "user2@example.com", Password: "pass", Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(user1).Error
require.NoError(t, err)
err = db.Create(user2).Error
require.NoError(t, err)
// 创建用户-机构关联
uo1 := &UserOrganization{UserId: user1.Id, OrgId: org.Id, RoleId: role.Id}
uo2 := &UserOrganization{UserId: user2.Id, OrgId: org.Id, RoleId: role.Id}
_, err = UserOrgInsert(ctx, db, uo1)
require.NoError(t, err)
_, err = UserOrgInsert(ctx, db, uo2)
require.NoError(t, err)
// 查询机构的所有成员
list, err := UserOrgFindByOrgId(ctx, db, org.Id)
require.NoError(t, err)
assert.Len(t, list, 2)
}
// TestUserOrgUpdate 测试更新用户-机构关联
func TestUserOrgUpdate(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建用户
user := &User{Username: "testuser", Email: "test@example.com", Password: "pass", Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(user).Error
require.NoError(t, err)
// 创建机构
org := createTestOrg(t, db)
// 创建2个角色
role1 := &Role{Name: "角色1", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
role2 := &Role{Name: "角色2", Code: "role_2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(role1).Error
require.NoError(t, err)
err = db.Create(role2).Error
require.NoError(t, err)
// 创建关联(使用角色1)
uo := &UserOrganization{UserId: user.Id, OrgId: org.Id, RoleId: role1.Id}
_, err = UserOrgInsert(ctx, db, uo)
require.NoError(t, err)
// 更新角色为角色2
uo.RoleId = role2.Id
err = UserOrgUpdate(ctx, db, uo)
require.NoError(t, err)
// 验证更新结果
updated, err := UserOrgFindOne(ctx, db, user.Id, org.Id)
require.NoError(t, err)
assert.Equal(t, role2.Id, updated.RoleId)
}
// TestUserOrgDelete 测试删除用户-机构关联
func TestUserOrgDelete(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建用户
user := &User{Username: "testuser", Email: "test@example.com", Password: "pass", Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(user).Error
require.NoError(t, err)
// 创建机构
org := createTestOrg(t, db)
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(role).Error
require.NoError(t, err)
// 创建关联
uo := &UserOrganization{UserId: user.Id, OrgId: org.Id, RoleId: role.Id}
_, err = UserOrgInsert(ctx, db, uo)
require.NoError(t, err)
// 删除关联
err = UserOrgDelete(ctx, db, user.Id, org.Id)
require.NoError(t, err)
// 验证关联已被删除
_, err = UserOrgFindOne(ctx, db, user.Id, org.Id)
require.Error(t, err)
assert.Equal(t, ErrNotFound, err)
}
// TestUserOrgCountByOrgId 测试统计机构成员数
func TestUserOrgCountByOrgId(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建机构
org := createTestOrg(t, db)
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(role).Error
require.NoError(t, err)
// 创建3个用户并关联到机构
for i := 1; i <= 3; i++ {
user := &User{
Username: "user" + string(rune('0'+i)),
Email: "user" + string(rune('0'+i)) + "@example.com",
Password: "pass",
Status: 1,
CreatedAt: now,
UpdatedAt: now,
}
err := db.Create(user).Error
require.NoError(t, err)
uo := &UserOrganization{UserId: user.Id, OrgId: org.Id, RoleId: role.Id}
_, err = UserOrgInsert(ctx, db, uo)
require.NoError(t, err)
}
// 统计成员数
count, err := UserOrgCountByOrgId(ctx, db, org.Id)
require.NoError(t, err)
assert.Equal(t, int64(3), count)
}
// ==================== RoleMenu Tests ====================
// TestRoleMenuSetForRole 测试全量设置角色的菜单
func TestRoleMenuSetForRole(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(role).Error
require.NoError(t, err)
// 创建3个菜单
menus := []Menu{
{Name: "菜单1", Path: "/1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now},
{Name: "菜单2", Path: "/2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now},
{Name: "菜单3", Path: "/3", SortOrder: 3, Status: 1, CreatedAt: now, UpdatedAt: now},
}
for i := range menus {
err := db.Create(&menus[i]).Error
require.NoError(t, err)
}
// 设置角色菜单(菜单1和菜单2)
menuIds := []int64{menus[0].Id, menus[1].Id}
err = RoleMenuSetForRole(ctx, db, role.Id, menuIds)
require.NoError(t, err)
// 验证
foundIds, err := RoleMenuFindByRoleId(ctx, db, role.Id)
require.NoError(t, err)
assert.Len(t, foundIds, 2)
assert.Contains(t, foundIds, menus[0].Id)
assert.Contains(t, foundIds, menus[1].Id)
// 重新设置(替换为菜单2和菜单3)
menuIds2 := []int64{menus[1].Id, menus[2].Id}
err = RoleMenuSetForRole(ctx, db, role.Id, menuIds2)
require.NoError(t, err)
// 验证替换结果
foundIds2, err := RoleMenuFindByRoleId(ctx, db, role.Id)
require.NoError(t, err)
assert.Len(t, foundIds2, 2)
assert.Contains(t, foundIds2, menus[1].Id)
assert.Contains(t, foundIds2, menus[2].Id)
}
// TestRoleMenuFindByRoleId 测试获取角色的菜单ID列表
func TestRoleMenuFindByRoleId(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(role).Error
require.NoError(t, err)
// 创建菜单
menu1 := &Menu{Name: "菜单1", Path: "/1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
menu2 := &Menu{Name: "菜单2", Path: "/2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(menu1).Error
require.NoError(t, err)
err = db.Create(menu2).Error
require.NoError(t, err)
// 设置角色菜单
err = RoleMenuSetForRole(ctx, db, role.Id, []int64{menu1.Id, menu2.Id})
require.NoError(t, err)
// 查询角色的菜单ID列表
menuIds, err := RoleMenuFindByRoleId(ctx, db, role.Id)
require.NoError(t, err)
assert.Len(t, menuIds, 2)
assert.Contains(t, menuIds, menu1.Id)
assert.Contains(t, menuIds, menu2.Id)
}
// TestRoleMenuFindByRoleIds 测试获取多个角色的菜单ID列表(去重)
func TestRoleMenuFindByRoleIds(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建2个角色
role1 := &Role{Name: "角色1", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
role2 := &Role{Name: "角色2", Code: "role_2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(role1).Error
require.NoError(t, err)
err = db.Create(role2).Error
require.NoError(t, err)
// 创建3个菜单
menus := []Menu{
{Name: "菜单1", Path: "/1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now},
{Name: "菜单2", Path: "/2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now},
{Name: "菜单3", Path: "/3", SortOrder: 3, Status: 1, CreatedAt: now, UpdatedAt: now},
}
for i := range menus {
err := db.Create(&menus[i]).Error
require.NoError(t, err)
}
// 角色1 -> 菜单1, 菜单2
err = RoleMenuSetForRole(ctx, db, role1.Id, []int64{menus[0].Id, menus[1].Id})
require.NoError(t, err)
// 角色2 -> 菜单2, 菜单3(菜单2重复)
err = RoleMenuSetForRole(ctx, db, role2.Id, []int64{menus[1].Id, menus[2].Id})
require.NoError(t, err)
// 查询多个角色的菜单ID(去重)
menuIds, err := RoleMenuFindByRoleIds(ctx, db, []int64{role1.Id, role2.Id})
require.NoError(t, err)
assert.Len(t, menuIds, 3) // 菜单1, 菜单2, 菜单3(去重后3个)
assert.Contains(t, menuIds, menus[0].Id)
assert.Contains(t, menuIds, menus[1].Id)
assert.Contains(t, menuIds, menus[2].Id)
}
// TestRoleMenuDeleteByRoleId 测试删除角色的所有菜单关联
func TestRoleMenuDeleteByRoleId(t *testing.T) {
db := setupOrgTestDB(t)
ctx := context.Background()
now := time.Now()
// 创建角色
role := &Role{Name: "角色", Code: "role_1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
err := db.Create(role).Error
require.NoError(t, err)
// 创建菜单
menu1 := &Menu{Name: "菜单1", Path: "/1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}
menu2 := &Menu{Name: "菜单2", Path: "/2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}
err = db.Create(menu1).Error
require.NoError(t, err)
err = db.Create(menu2).Error
require.NoError(t, err)
// 设置角色菜单
err = RoleMenuSetForRole(ctx, db, role.Id, []int64{menu1.Id, menu2.Id})
require.NoError(t, err)
// 删除角色的所有菜单关联
err = RoleMenuDeleteByRoleId(ctx, db, role.Id)
require.NoError(t, err)
// 验证菜单关联已被删除
menuIds, err := RoleMenuFindByRoleId(ctx, db, role.Id)
require.NoError(t, err)
assert.Empty(t, menuIds)
}