Files
qitongxue-api/internal/logic/admin_level_test.go
2026-09-29 10:57:01 +08:00

79 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logic
import (
"testing"
"time"
"github.com/gogf/gf/v2/os/gtime"
"tool-api/internal/consts"
"tool-api/internal/model/entity"
)
// TestCountActiveMembers_PermanentCounted 看板「有效会员」必须计入永久会员
// (level_expire_at = NULL,管理员手动分配)。这是本次修复(#24)的核心回归点:
// 旧 SQL 用 `level_expire_at IS NOT NULL` 把永久会员全部漏掉了。
func TestCountActiveMembers_PermanentCounted(t *testing.T) {
future := gtime.New(time.Now().Add(24 * time.Hour))
past := gtime.New(time.Now().Add(-24 * time.Hour))
users := []*entity.Users{
{LevelKey: "v2", LevelExpireAt: nil}, // ① 永久(NULL)→ 应计入
{LevelKey: "v2", LevelExpireAt: future}, // ② 未过期 → 应计入
{LevelKey: "v2", LevelExpireAt: past}, // ③ 已过期 → 回落默认等级,不计入
}
if got := countActiveMembers(users); got != 2 {
t.Fatalf("countActiveMembers=%d want 2", got)
}
}
// TestLevelDistribution_EffectiveKey 等级分布按「生效等级」分组:
// 已过期用户必须落入默认等级桶,而不是其原始 level_key。
func TestLevelDistribution_EffectiveKey(t *testing.T) {
future := gtime.New(time.Now().Add(24 * time.Hour))
past := gtime.New(time.Now().Add(-24 * time.Hour))
users := []*entity.Users{
{LevelKey: "v2", LevelExpireAt: nil},
{LevelKey: "v2", LevelExpireAt: future},
{LevelKey: "v2", LevelExpireAt: past},
}
dist := levelDistribution(users)
if dist["v2"] != 2 {
t.Fatalf("v2 桶=%d want 2 (%v)", dist["v2"], dist)
}
if dist[consts.DefaultLevelKey] != 1 {
t.Fatalf("默认等级桶=%d want 1 (%v)", dist[consts.DefaultLevelKey], dist)
}
}
// TestCountActiveMembers_DefaultExcluded 默认等级(含空 key)不算有效会员。
func TestCountActiveMembers_DefaultExcluded(t *testing.T) {
users := []*entity.Users{
{LevelKey: consts.DefaultLevelKey, LevelExpireAt: nil},
{LevelKey: "", LevelExpireAt: nil},
}
if got := countActiveMembers(users); got != 0 {
t.Fatalf("countActiveMembers=%d want 0", got)
}
if n := countActiveMembers(nil); n != 0 {
t.Fatalf("nil 应返回 0,got %d", n)
}
}
// TestValidateLevelKeyUnchanged 编辑等级时 level_key 是跨端契约字段,不允许变更(T01.6)。
// 服务端闸门:前端把输入框 disabled 只是体验层,这里固化「变更即报错」的行为,
// 取消失败回归(例如未来有人误把 level_key 写进编辑 data map)。
func TestValidateLevelKeyUnchanged(t *testing.T) {
// 未变更 → 放行
if err := validateLevelKeyUnchanged("v2", "v2"); err != nil {
t.Fatalf("相同 level_key 应放行,got err=%v", err)
}
// 变更 → 报错
if err := validateLevelKeyUnchanged("v2", "v3"); err == nil {
t.Fatalf("变更 level_key 应报错,got nil")
}
// 清空(旧展开式回填的典型故障)→ 报错
if err := validateLevelKeyUnchanged("v2", ""); err == nil {
t.Fatalf("清空 level_key 应报错,got nil")
}
}