Files
iotlcm/server/internal/logic/app/app_customer_scope_test.go
T

149 lines
6.9 KiB
Go

package app
import (
"context"
"reflect"
"testing"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
func TestAppCustomerScopeSQL(t *testing.T) {
ctx := context.Background()
previous := gdb.GetConfig("default")
if err := gdb.SetConfigGroup("default", gdb.ConfigGroup{{Type: "sqlite", Link: "sqlite::@file(:memory:)", MaxOpenConnCount: 1}}); err != nil {
t.Fatal(err)
}
database := g.DB()
t.Cleanup(func() {
if err := database.GetCore().ClearCacheAll(ctx); err != nil {
t.Error(err)
}
if err := database.Close(ctx); err != nil {
t.Error(err)
}
if err := gdb.SetConfigGroup("default", previous); err != nil {
t.Error(err)
}
})
if err := database.GetCore().ClearCacheAll(ctx); err != nil {
t.Fatal(err)
}
statements := []string{
"CREATE TABLE sys_menu (menu_id INTEGER PRIMARY KEY, perms TEXT, status TEXT, deleted_at DATETIME)",
"INSERT INTO sys_menu VALUES (1,'agent:dept:list','0',NULL)",
"CREATE TABLE sys_config (config_id INTEGER PRIMARY KEY, tenant_id TEXT, config_key TEXT, config_value TEXT, deleted_at DATETIME)",
"INSERT INTO sys_config VALUES (1,'A','iot.register.app.dept','900',NULL)",
"CREATE TABLE sys_dept (dept_id INTEGER PRIMARY KEY, tenant_id TEXT, parent_id INTEGER, dept_type INTEGER, order_num INTEGER, dept_name TEXT, dept_key TEXT, status TEXT, deleted_at DATETIME)",
"INSERT INTO sys_dept VALUES (100,'A',0,1,0,'顶级','TOP','0',NULL),(101,'A',100,1,1,'客户甲','A101','0',NULL),(102,'A',101,1,2,'客户乙','A102','1',NULL),(103,'A',100,0,3,'普通部门','D103','0',NULL),(104,'A',100,1,4,'已删除','A104','0','2026-01-01'),(200,'B',0,1,5,'其他租户','B200','0',NULL),(900,'A',100,1,6,'注册组织','R900','0',NULL),(901,'A',900,1,7,'注册下级','R901','0',NULL)",
"CREATE TABLE sys_role_dept (role_id INTEGER, dept_id INTEGER, tenant_id TEXT)",
"INSERT INTO sys_role_dept VALUES (9,102,'A'),(9,200,'B')",
}
for _, statement := range statements {
if _, err := database.Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
t.Run("卡统计包含全部状态并隔离租户与删除记录", func(t *testing.T) {
statements := []string{
"CREATE TABLE t_sim_card_info (id INTEGER PRIMARY KEY, tenant_id TEXT, dept_id INTEGER, boss_card_status INTEGER, package_status INTEGER, deleted_at DATETIME)",
"INSERT INTO t_sim_card_info VALUES (1,'A',101,2,2,NULL),(2,'A',101,2,3,NULL),(3,'A',101,4,2,NULL),(4,'A',101,1,0,NULL),(5,'A',101,6,0,NULL),(6,'A',101,7,0,NULL),(7,'A',101,8,0,NULL),(8,'A',101,9,0,NULL),(9,'A',101,NULL,NULL,NULL),(10,'A',101,88,0,NULL),(11,'A',101,2,2,'2026-01-01'),(12,'B',101,2,2,NULL),(13,'A',102,4,2,NULL)",
}
for _, statement := range statements {
if _, err := database.Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
stats, err := appCardStatsByDept(ctx, "A", []int64{101, 999})
if err != nil {
t.Fatal(err)
}
stat := stats[101]
if stat == nil || stat.CardCount != 10 || stat.NormalCardCount != 1 || len(stats) != 1 {
t.Fatalf("unexpected stats: stat=%+v, departments=%d", stat, len(stats))
}
expected := []model.AppCustomerStatusCount{{Status: 0, Count: 1}, {Status: 1, Count: 1}, {Status: 2, Count: 2}, {Status: 4, Count: 1}, {Status: 6, Count: 1}, {Status: 7, Count: 1}, {Status: 8, Count: 1}, {Status: 9, Count: 1}, {Status: 88, Count: 1}}
if !reflect.DeepEqual(stat.CardStatusCounts, expected) {
t.Fatalf("actual=%+v expected=%+v", stat.CardStatusCounts, expected)
}
item := appEnterpriseCustomerModel(&entity.SysDept{DeptId: 101}, nil, 0, stat)
if !reflect.DeepEqual(item.CardStatusCounts, expected) || item.CardCount != 10 {
t.Fatalf("model lost card status counts: %+v", item)
}
packageCounts := make(map[int]int)
for _, count := range stat.PackageStatusCounts {
packageCounts[count.Status] = count.Count
}
if !reflect.DeepEqual(packageCounts, map[int]int{-1: 1, 0: 6, 2: 2, 3: 1}) {
t.Fatalf("unexpected package counts: %+v", packageCounts)
}
if !reflect.DeepEqual(item.PackageStatusCounts, stat.PackageStatusCounts) {
t.Fatalf("model lost package counts: %+v", item)
}
if _, err := database.Exec(ctx, "INSERT INTO t_sim_card_info VALUES (14,'A',105,2,2,NULL),(15,'A',105,2,2,NULL),(16,'A',105,2,2,NULL),(17,'A',105,2,2,NULL),(18,'A',105,2,2,NULL),(19,'A',105,2,2,NULL),(20,'A',105,2,3,NULL),(21,'A',105,2,3,NULL)"); err != nil {
t.Fatal(err)
}
activatedStats, err := appCardStatsByDept(ctx, "A", []int64{105})
if err != nil {
t.Fatal(err)
}
activated := activatedStats[105]
if activated == nil || activated.CardCount != 8 || activated.NormalCardCount != 6 || !reflect.DeepEqual(activated.CardStatusCounts, []model.AppCustomerStatusCount{{Status: 2, Count: 8}}) {
t.Fatalf("unexpected activated stats: %+v", activated)
}
if !reflect.DeepEqual(activated.PackageStatusCounts, []model.AppCustomerStatusCount{{Status: 2, Count: 6}, {Status: 3, Count: 2}}) {
t.Fatalf("expired packages must not be counted as stopped cards: %+v", activated)
}
})
user := &entity.SysUser{UserId: 7, TenantId: "A", DeptId: 100}
cases := []struct {
name, scope string
expected []int64
}{
{"全部仍限制租户和企业类型", consts.SysRoleDataScopeAll, []int64{101, 102}},
{"直属下级不含孙级", consts.SysRoleDataScopeOrgNextLevel, []int64{101}},
{"本级及下级包含孙级", consts.SysRoleDataScopeDeptAndBelow, []int64{101, 102}},
{"自定义指定孙级", consts.SysRoleDataScopeCustom, []int64{102}},
{"仅本级没有客户", consts.SysRoleDataScopeDept, []int64{}},
{"仅本人没有组织权限", consts.SysRoleDataScopePersonal, []int64{}},
{"未知范围拒绝", "invalid", []int64{}},
}
for _, item := range cases {
t.Run(item.name, func(t *testing.T) {
scopeCtx := contexts.Set(ctx, &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: user.UserId, TenantId: user.TenantId, DeptId: user.DeptId}}})
contexts.SetDataValue(scopeCtx, "currentRoleId", "9")
contexts.SetDataValue(scopeCtx, "currentRoleDataScope", item.scope)
rows, err := appEnterpriseAuthorizedCustomerDepts(scopeCtx, user)
if err != nil {
t.Fatal(err)
}
actual := appDeptIds(rows)
if !reflect.DeepEqual(actual, item.expected) {
t.Fatalf("actual=%v expected=%v", actual, item.expected)
}
for _, candidate := range []int64{100, 101, 102, 103, 104, 200, 900, 901, 999} {
visible, err := appEnterpriseCustomerDeptVisible(scopeCtx, user, candidate)
if err != nil {
t.Fatal(err)
}
expected := false
for _, id := range item.expected {
if candidate == id {
expected = true
}
}
if visible != expected {
t.Fatalf("detail visibility for %d: actual=%v expected=%v", candidate, visible, expected)
}
}
})
}
}