chore: 并入 iotlcm-admin-svr 历史到 admin-svr/(原提交 49818c6)

This commit is contained in:
MiFaZhan
2026-11-02 13:27:59 +08:00
1250 changed files with 154111 additions and 0 deletions
@@ -0,0 +1,437 @@
package system
import (
"context"
"os"
"os/exec"
"path/filepath"
"slices"
"strings"
"testing"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcfg"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rolepolicy"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rolesync"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/agent"
_ "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/memorydb"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
)
func TestRoleMenuTemplateValidationIsolation(t *testing.T) {
if os.Getenv("ROLE_TEMPLATE_TEST_CHILD") != "1" {
configPath := filepath.Join(t.TempDir(), "config.yaml")
if err := os.WriteFile(configPath, []byte("database:\n default:\n type: sqlite\n link: sqlite::@file(:memory:)\n memorydb:\n link: \"\"\n"), 0600); err != nil {
t.Fatal(err)
}
executable, err := os.Executable()
if err != nil {
t.Fatal(err)
}
command := exec.Command(executable, "-test.run=^TestRoleMenuTemplateValidationIsolation$", "-test.v")
command.Env = append(os.Environ(), "ROLE_TEMPLATE_TEST_CHILD=1", "GF_GCFG_FILE="+configPath)
output, err := command.CombinedOutput()
if err != nil {
t.Fatalf("isolated role tests failed: %v\n%s", err, output)
}
t.Log(string(output))
return
}
originalAdapter := g.Cfg().GetAdapter()
adapter, err := gcfg.NewAdapterContent("database:\n default:\n type: sqlite\n link: sqlite::@file(:memory:)\n memorydb:\n link: \"\"\n", "yaml")
if err != nil {
t.Fatal(err)
}
g.Cfg().SetAdapter(adapter)
t.Cleanup(func() { g.Cfg().SetAdapter(originalAdapter) })
if err := gdb.SetConfig(gdb.Config{"default": {{Type: "sqlite", Link: "sqlite::@file(:memory:)"}}}); err != nil {
t.Fatal(err)
}
ctx := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 1, TenantId: "000000", DeptId: 100, Roles: []model.Role{{RoleId: consts.SuperAdminRoleId}}}}})
t.Cleanup(func() { _ = g.DB().Close(ctx) })
for _, statement := range []string{
"CREATE TABLE sys_config (tenant_id TEXT, config_key TEXT, config_value TEXT)",
"CREATE TABLE sys_role (role_id INTEGER PRIMARY KEY, tenant_id TEXT, dept_id INTEGER, created_dept INTEGER, status TEXT, is_pass INTEGER, data_scope TEXT, role_name TEXT, role_sort INTEGER, menu_check_strictly INTEGER, dept_check_strictly INTEGER, created_by INTEGER, created_at DATETIME, updated_by INTEGER, updated_at DATETIME, deleted_by INTEGER, remark TEXT, deleted_at DATETIME)",
"CREATE TABLE sys_role_menu (tenant_id TEXT, role_id INTEGER, menu_id INTEGER, data_scope TEXT)",
"CREATE TABLE sys_user_role (tenant_id TEXT, user_id INTEGER, role_id INTEGER)",
"CREATE TABLE sys_role_dept (tenant_id TEXT, role_id INTEGER, dept_id INTEGER)",
"INSERT INTO sys_config VALUES ('000000','agent.role.template.role_id','82')",
"INSERT INTO sys_role (role_id,tenant_id,dept_id,created_dept,status,is_pass,data_scope,deleted_at) VALUES (82,'000000',0,100,'0',0,'4',NULL)",
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
service := NewSysRole()
t.Run("普通角色新增菜单不受无效模板影响", func(t *testing.T) {
if err := service.RoleMenu(ctx, 200, []int64{10, 11}, nil); err != nil {
t.Fatal(err)
}
count, err := g.DB().Model("sys_role_menu").Where("role_id", 200).Count()
if err != nil || count != 2 {
t.Fatalf("menu count %d: %v", count, err)
}
})
t.Run("普通角色修改菜单不受无效模板影响", func(t *testing.T) {
if err := service.RoleMenu(ctx, 200, []int64{11, 12}, nil); err != nil {
t.Fatal(err)
}
count, err := g.DB().Model("sys_role_menu").Where("role_id", 200).Where("menu_id", 10).Count()
if err != nil || count != 0 {
t.Fatalf("removed menu count %d: %v", count, err)
}
})
t.Run("模板仍禁止全部按钮数据权限", func(t *testing.T) {
err := service.RoleMenu(ctx, 82, []int64{10}, map[int64]string{10: consts.SysRoleDataScopeAll})
if err == nil || !strings.Contains(err.Error(), "模板按钮") {
t.Fatalf("expected template restriction: %v", err)
}
})
t.Run("无效模板仍禁止删除", func(t *testing.T) {
_, err := service.Delete(ctx, &model.SysRoleDeleteParam{RoleId: 82})
if err == nil || !strings.Contains(err.Error(), "模板不能删除") {
t.Fatalf("expected template deletion rejection: %v", err)
}
})
t.Run("批量删除不能包含模板", func(t *testing.T) {
_, err := service.Delete(ctx, &model.SysRoleDeleteParam{RoleIds: []int64{200, 82}})
if err == nil || !strings.Contains(err.Error(), "模板不能删除") {
t.Fatalf("expected batch deletion rejection: %v", err)
}
})
t.Run("非管理员不能绕过无效模板授权", func(t *testing.T) {
limited := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 2, TenantId: "000000", DeptId: 175}}})
if err := service.RoleMenu(limited, 201, []int64{10}, nil); err == nil {
t.Fatal("invalid template must fail closed")
}
count, err := g.DB().Model("sys_role_menu").Where("role_id", 201).Count()
if err != nil || count != 0 {
t.Fatalf("unauthorized menu count %d: %v", count, err)
}
})
t.Run("运行时模板校验仍然严格", func(t *testing.T) {
if _, err := rolepolicy.Template(ctx); err == nil {
t.Fatal("invalid template was accepted")
}
})
t.Run("无关角色不读取模板角色实体", func(t *testing.T) {
template, err := rolepolicy.TemplateForRoles(ctx, 200)
if err != nil || template != nil {
t.Fatalf("unexpected template: %+v %v", template, err)
}
})
t.Run("已删除模板仍保留身份保护", func(t *testing.T) {
if _, err := g.DB().Exec(ctx, "DELETE FROM sys_role WHERE role_id=82"); err != nil {
t.Fatal(err)
}
template, err := rolepolicy.TemplateForRoles(ctx, 82)
if err != nil || template == nil || template.RoleId != 82 {
t.Fatalf("template identity lost: %+v %v", template, err)
}
})
t.Run("错误参数不阻断无关角色但不能用于授权", func(t *testing.T) {
if _, err := g.DB().Exec(ctx, "UPDATE sys_config SET config_value='invalid'"); err != nil {
t.Fatal(err)
}
if err := service.RoleMenu(ctx, 202, []int64{10}, nil); err != nil {
t.Fatal(err)
}
if _, err := rolepolicy.Template(ctx); err == nil {
t.Fatal("invalid configuration must fail strict validation")
}
})
t.Run("平台管理员权限加载不依赖无效模板", func(t *testing.T) {
for _, statement := range []string{
"UPDATE sys_config SET config_value='82'",
"ALTER TABLE sys_role ADD COLUMN role_key TEXT",
"INSERT INTO sys_role (role_id,tenant_id,dept_id,status,role_key,data_scope) VALUES (1,'000000',100,'0','admin','1'),(102,'000000',175,'0','agent','1')",
"CREATE TABLE sys_dept (dept_id INTEGER PRIMARY KEY, tenant_id TEXT, parent_id INTEGER, dept_role INTEGER, status TEXT, ancestors TEXT, dept_type INTEGER, order_num INTEGER DEFAULT 0, deleted_at DATETIME)",
"INSERT INTO sys_dept (dept_id,tenant_id,parent_id,dept_role,status,deleted_at) VALUES (100,'000000',0,1,'0',NULL),(175,'000000',100,102,'0',NULL)",
"CREATE TABLE sys_menu (menu_id INTEGER PRIMARY KEY, menu_name TEXT, parent_id INTEGER, path TEXT, menu_type TEXT, order_num INTEGER, perms TEXT, status TEXT, deleted_at DATETIME)",
"INSERT INTO sys_menu VALUES (10,'授权功能',0,'allowed','C',1,'system:test:allowed','0',NULL),(11,'受限功能',0,'restricted','C',2,'system:test:restricted','0',NULL)",
"CREATE TABLE sys_user (user_id INTEGER PRIMARY KEY, tenant_id TEXT, dept_id INTEGER, user_name TEXT, status TEXT, deleted_at DATETIME)",
"INSERT INTO sys_user VALUES (1,'000000',100,'admin','0',NULL),(2,'000000',175,'agent','0',NULL)",
"CREATE TABLE sys_user_post (tenant_id TEXT, user_id INTEGER, post_id INTEGER)",
"INSERT INTO sys_user_role VALUES ('000000',1,1),('000000',2,102)",
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
accessCodes, _, err := NewSysAuth().GetUserAccessCodeList(ctx, 1)
if err != nil {
t.Fatal(err)
}
if !slices.Contains(accessCodes, "cpm:system:test:allowed") {
t.Fatalf("administrator permissions missing: %v", accessCodes)
}
menus, err := NewSysMenu().GetUserMenu(ctx)
if err != nil || len(menus) != 2 {
t.Fatalf("administrator menu loading failed: %v %v", menus, err)
}
})
t.Run("不能仅凭旧令牌声称是平台管理员", func(t *testing.T) {
stale := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 2, TenantId: "000000", DeptId: 175, Roles: []model.Role{{RoleId: consts.SuperAdminRoleId}}}}})
if _, _, err := NewSysAuth().GetUserAccessCodeList(stale, 2); err == nil {
t.Fatal("stale administrator claim bypassed template validation")
}
})
t.Run("停用平台管理员角色不能跳过模板校验", func(t *testing.T) {
if _, err := g.DB().Exec(ctx, "UPDATE sys_role SET status='1' WHERE role_id=1"); err != nil {
t.Fatal(err)
}
defer func() {
if _, err := g.DB().Exec(ctx, "UPDATE sys_role SET status='0' WHERE role_id=1"); err != nil {
t.Error(err)
}
}()
if _, _, err := NewSysAuth().GetUserAccessCodeList(ctx, 1); err == nil {
t.Fatal("disabled administrator role bypassed validation")
}
})
t.Run("跨租户管理员标记不能跳过模板校验", func(t *testing.T) {
other := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 1, TenantId: "other", DeptId: 100, Roles: []model.Role{{RoleId: consts.SuperAdminRoleId}}}}})
if _, _, err := NewSysAuth().GetUserAccessCodeList(other, 1); err == nil {
t.Fatal("cross-tenant administrator claim bypassed validation")
}
})
t.Run("模板参数格式异常不阻断平台管理员", func(t *testing.T) {
if _, err := g.DB().Exec(ctx, "UPDATE sys_config SET config_value='invalid'"); err != nil {
t.Fatal(err)
}
if _, _, err := NewSysAuth().GetUserAccessCodeList(ctx, 1); err != nil {
t.Fatal(err)
}
})
t.Run("平台单独扩大默认角色权限后菜单及鉴权均生效且不扩大数据范围", func(t *testing.T) {
for _, statement := range []string{
"UPDATE sys_config SET config_value='82'",
"INSERT INTO sys_role (role_id,tenant_id,dept_id,created_dept,status,is_pass,data_scope) VALUES (82,'000000',100,100,'0',1,'4')",
"INSERT INTO sys_role_menu VALUES ('000000',82,10,'0'),('000000',102,10,'0'),('000000',102,11,'0')",
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
agent := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 2, TenantId: "000000", DeptId: 175}}})
accessCodes, roleCodes, err := NewSysAuth().GetUserAccessCodeList(agent, 2)
if err != nil {
t.Fatal(err)
}
if !slices.Contains(accessCodes, "cpm:system:test:allowed") || !slices.Contains(accessCodes, "cpm:system:test:restricted") {
t.Fatalf("agent menu boundary violated: %v", accessCodes)
}
menus, err := NewSysMenu().GetUserMenu(agent)
if err != nil || len(menus) != 2 {
t.Fatalf("individual menus missing: %v %v", menus, err)
}
if len(roleCodes) != 2 || !strings.HasSuffix(roleCodes[0], "|4") || !strings.HasSuffix(roleCodes[1], "|4") {
t.Fatalf("agent data scope boundary violated: %v", roleCodes)
}
})
t.Run("平台从角色管理扩大普通角色权限不受默认角色限制", func(t *testing.T) {
for _, statement := range []string{
"DELETE FROM sys_role_menu WHERE role_id=102 AND menu_id=11",
"INSERT INTO sys_role(role_id,tenant_id,dept_id,created_dept,status,data_scope,role_key) VALUES(103,'000000',175,175,'0','4','special')",
"INSERT INTO sys_user VALUES(3,'000000',175,'special','0',NULL)",
"INSERT INTO sys_user_role VALUES('000000',3,103)",
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
if _, err := service.Edit(rolesync.DeferRecording(ctx), &model.SysRoleEditParam{RoleId: 103, MenuIds: []int64{11}}); err != nil {
t.Fatal(err)
}
special := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 3, TenantId: "000000", DeptId: 175}}})
codes, _, err := NewSysAuth().GetUserAccessCodeList(special, 3)
if err != nil || !slices.Contains(codes, "cpm:system:test:restricted") {
t.Fatalf("saved permission did not reach API authorization: %v %v", codes, err)
}
menus, err := NewSysMenu().GetUserMenu(special)
if err != nil || len(menus) != 1 || menus[0].MenuId != 11 {
t.Fatalf("saved permission did not reach navigation: %v %v", menus, err)
}
if _, err := g.DB().Exec(ctx, "DELETE FROM sys_role_menu WHERE role_id=103"); err != nil {
t.Fatal(err)
}
codes, _, err = NewSysAuth().GetUserAccessCodeList(special, 3)
if err != nil || slices.Contains(codes, "cpm:system:test:restricted") {
t.Fatalf("revoked role permission remained usable: %v %v", codes, err)
}
})
t.Run("角色详情说明模板和默认角色身份", func(t *testing.T) {
for _, test := range []struct {
id int64
template, defaultRole bool
}{{82, true, false}, {102, false, true}, {103, false, false}} {
role, err := service.View(ctx, &model.SysRoleViewParam{RoleId: test.id})
if err != nil {
t.Fatal(err)
}
if role.IsTemplateRole != test.template || role.IsDeptDefaultRole != test.defaultRole {
t.Fatalf("wrong role metadata: %+v", role)
}
}
})
t.Run("非平台管理员不能单独修改模板菜单或数据范围", func(t *testing.T) {
operator := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 2, TenantId: "000000", DeptId: 175}}})
if err := service.RoleMenu(operator, 82, []int64{10}, nil); err == nil || !strings.Contains(err.Error(), "仅平台超级管理员") {
t.Fatalf("template menu change was not rejected: %v", err)
}
if err := service.EditRoleDataScope(operator, &model.SysRoleDataScopeEditParam{RoleId: 82, DataScope: consts.SysRoleDataScopeDeptAndBelow}); err == nil || !strings.Contains(err.Error(), "仅平台超级管理员") {
t.Fatalf("template data scope change was not rejected: %v", err)
}
})
t.Run("企业入口允许已有下发角色时新增多个普通角色", func(t *testing.T) {
for _, roleName := range []string{"财务", "客服"} {
roleID, err := agent.NewAgentRole().RoleSave(ctx, &model.AgentRoleSaveParam{RoleName: roleName, RoleKey: "staff", MenuIds: []int64{10}, DataScope: consts.SysRoleDataScopePersonal})
if err != nil {
t.Fatal(err)
}
record, err := g.DB().Model("sys_role").Where("role_id", roleID).One()
if err != nil || record["is_pass"].Int() != 0 || record["data_scope"].String() != consts.SysRoleDataScopePersonal {
t.Fatalf("ordinary role was changed: %v %v", record, err)
}
}
})
t.Run("配置平台模板后历史下发标记不限制普通角色维护", func(t *testing.T) {
_, err := agent.NewAgentRole().RoleSave(ctx, &model.AgentRoleSaveParam{RoleName: "历史标记角色", RoleKey: "legacy", IsPass: 1})
if err != nil {
t.Fatal(err)
}
})
t.Run("平台模板由参数识别不依赖隐藏下发标记", func(t *testing.T) {
_, err := agent.NewAgentRole().RoleSave(rolesync.DeferRecording(ctx), &model.AgentRoleSaveParam{RoleId: 82, RoleName: "模板", RoleKey: "template", MenuIds: []int64{10}, IsPass: 0})
if err != nil {
t.Fatal(err)
}
template, err := rolepolicy.Template(ctx)
if err != nil || template == nil || template.RoleId != 82 || template.IsPass != 0 {
t.Fatalf("configured template not recognized: %+v %v", template, err)
}
})
t.Run("企业入口拒绝错误历史传递标记", func(t *testing.T) {
_, err := agent.NewAgentRole().RoleSave(ctx, &model.AgentRoleSaveParam{RoleName: "无效标记", RoleKey: "invalid", IsPass: 2})
if err == nil || !strings.Contains(err.Error(), "传递标记无效") {
t.Fatalf("invalid legacy marker was accepted: %v", err)
}
})
t.Run("配置模板后历史下发标记不阻断普通角色删除", func(t *testing.T) {
for _, statement := range []string{
"INSERT INTO sys_role(role_id,tenant_id,dept_id,created_dept,status,is_pass,data_scope) VALUES(600,'000000',100,100,'0',1,'4')",
"UPDATE sys_role SET created_dept=100 WHERE role_id=102",
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
if _, err := service.Delete(ctx, &model.SysRoleDeleteParam{RoleId: 600}); err != nil {
t.Fatal(err)
}
})
t.Run("授权范围不能超出当前操作员有效角色", func(t *testing.T) {
if _, err := g.DB().Exec(ctx, "INSERT INTO sys_role(role_id,tenant_id,dept_id,created_dept,status,is_pass,data_scope,role_key) VALUES(501,'000000',175,175,'0',0,'4','staff')"); err != nil {
t.Fatal(err)
}
if _, err := g.DB().Exec(ctx, "INSERT INTO sys_user_role VALUES('000000',3,501)"); err != nil {
t.Fatal(err)
}
operator := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 3, TenantId: "000000", DeptId: 175}}})
if err := service.RoleMenu(operator, 501, []int64{10}, nil); err == nil || !strings.Contains(err.Error(), "超出") {
t.Fatalf("operator without permission granted it: %v", err)
}
if _, err := g.DB().Exec(ctx, "INSERT INTO sys_role_menu VALUES('000000',501,10,'0')"); err != nil {
t.Fatal(err)
}
if err := service.RoleMenu(operator, 501, []int64{10}, nil); err != nil {
t.Fatal(err)
}
if _, err := g.DB().Exec(ctx, "UPDATE sys_role SET status='1' WHERE role_id=501"); err != nil {
t.Fatal(err)
}
if err := service.RoleMenu(operator, 501, []int64{10}, nil); err == nil {
t.Fatal("disabled operator role granted permission")
}
})
t.Run("展示祖先兼容旧请求但不写入实际授权", func(t *testing.T) {
for _, statement := range []string{
"INSERT INTO sys_menu VALUES (900,'展示目录',0,'display','M',0,'','0',NULL),(901,'未授权父菜单',900,'parent','C',0,'system:parent:list','0',NULL)",
"UPDATE sys_menu SET parent_id=901 WHERE menu_id=10",
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
operator := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 2, TenantId: "000000", DeptId: 175}}})
tree, assignable, err := agent.NewAgentMenu().AllowedMenuTree(operator, 175)
if err != nil {
t.Fatal(err)
}
if !slices.Contains(assignable, 10) || slices.Contains(assignable, 900) || slices.Contains(assignable, 901) {
t.Fatalf("display ancestors leaked into assignable IDs: %v", assignable)
}
if len(tree) != 3 || !slices.ContainsFunc(tree, func(menu *model.SysMenuTreeModel) bool { return menu.MenuId == 901 && menu.ParentId == 900 }) || !slices.ContainsFunc(tree, func(menu *model.SysMenuTreeModel) bool { return menu.MenuId == 10 && menu.ParentId == 901 }) {
t.Fatalf("display hierarchy is incomplete: %+v", tree)
}
if err := service.RoleMenu(operator, 502, []int64{900, 901, 10}, nil); err != nil {
t.Fatal(err)
}
var stored []int64
values, err := g.DB().Model("sys_role_menu").Where("role_id", 502).Array("menu_id")
if err != nil {
t.Fatal(err)
}
for _, value := range values {
stored = append(stored, value.Int64())
}
if len(stored) != 1 || stored[0] != 10 {
t.Fatalf("display-only permissions were persisted: %v", stored)
}
newRole, err := agent.NewAgentRole().RoleSave(rolesync.DeferRecording(operator), &model.AgentRoleSaveParam{
RoleName: "下级测试角色", RoleKey: "scoped-agent", MenuIds: []int64{900, 901, 10},
})
if err != nil {
t.Fatal(err)
}
storedMenus, err := g.DB().Model("sys_role_menu").Where("role_id", newRole).Array("menu_id")
if err != nil || len(storedMenus) != 1 || storedMenus[0].Int64() != 10 {
t.Fatalf("agent save did not preserve the same authorization boundary: %v %v", storedMenus, err)
}
if err := service.RoleMenu(operator, 502, []int64{10, 11}, nil); err == nil {
t.Fatal("unrelated permission was accepted")
}
count, err := g.DB().Model("sys_role_menu").Where("role_id", 502).Count()
if err != nil || count != 1 {
t.Fatalf("failed validation changed permissions: %d %v", count, err)
}
})
t.Run("默认角色缺失明确报错而不是静默返回404", func(t *testing.T) {
if _, err := g.DB().Exec(ctx, "UPDATE sys_dept SET dept_role=0 WHERE dept_id=175"); err != nil {
t.Fatal(err)
}
defer func() { _, _ = g.DB().Exec(ctx, "UPDATE sys_dept SET dept_role=102 WHERE dept_id=175") }()
if _, err := rolepolicy.RestrictMenus(ctx, "000000", 175, []int64{10}); err == nil || !strings.Contains(err.Error(), "未关联默认角色") {
t.Fatalf("missing role must be actionable: %v", err)
}
operator := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 2, TenantId: "000000", DeptId: 175}}})
if _, err := g.DB().Exec(ctx, "UPDATE sys_dept SET dept_type=1 WHERE dept_id=175"); err != nil {
t.Fatal(err)
}
if err := agent.NewAgentDept().EnsureCurrentDeptDefaultRole(operator); err == nil {
t.Fatal("missing default role was not reported")
}
count, err := g.DB().Model("sys_user_role").Where("user_id", 2).Count()
if err != nil || count != 1 {
t.Fatalf("read request changed user roles: %d %v", count, err)
}
})
}