l1StatusPlaceholder_audit_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package perm_test
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. "github.com/zeromicro/go-zero/core/stores/sqlx"
  9. "perms-system-server/internal/model/perm"
  10. "perms-system-server/internal/testutil"
  11. )
  12. // ---------------------------------------------------------------------------
  13. // 审计 L-1(第 8 轮)—— FindAllCodesByProductCode / DisableNotInCodesWithTx 的
  14. // `status = ?` 必须是真正的参数占位符,而不是 fmt.Sprintf("%d") 回填。
  15. //
  16. // 测试策略:往同一 productCode 里塞 status ∈ {1, 2, 99} 三类行(99 模拟未来枚举值,
  17. // 例如 "审核中"),断言:
  18. // - FindAllCodesByProductCode 只返回 status=1 的 code,不会把 99 误解成"非零即启用"。
  19. // - DisableNotInCodesWithTx 只影响 status=1 → 2 的跃迁,不得触碰 status=99。
  20. // 如果回退成 "WHERE status = 1" 的 Sprintf 版本,这两个断言仍会过;所以额外追加:
  21. // - 用"空白不在白名单"的 DisableNotInCodesWithTx(codes=nil 分支)二次验证只禁用
  22. // 已启用行,不扫到 status=99;这一条专门防御未来有人把 consts.StatusEnabled 的
  23. // 类型改成 int8/枚举时,%d 变成 "%d(1)" 之类退化字面量。
  24. // ---------------------------------------------------------------------------
  25. // TC-0986: 非 {1,2} 的未来扩展状态必须被过滤掉;只认 status=1 为 enabled。
  26. func TestSysPermModel_L1_FindAllCodes_StrictlyEqualEnabled(t *testing.T) {
  27. ctx := context.Background()
  28. conn := testutil.GetTestSqlConn()
  29. m := newTestSysPermModel(t)
  30. productCode := "l1_strict_" + testutil.UniqueId()
  31. now := time.Now().Unix()
  32. rows := []struct {
  33. code string
  34. status int64
  35. }{
  36. {"ena_" + testutil.UniqueId(), 1},
  37. {"dis_" + testutil.UniqueId(), 2},
  38. {"rev_" + testutil.UniqueId(), 99},
  39. }
  40. ids := make([]int64, 0, len(rows))
  41. for _, r := range rows {
  42. res, err := m.Insert(ctx, &perm.SysPerm{
  43. ProductCode: productCode, Name: "n", Code: r.code,
  44. Status: r.status, CreateTime: now, UpdateTime: now,
  45. })
  46. require.NoError(t, err)
  47. id, _ := res.LastInsertId()
  48. ids = append(ids, id)
  49. }
  50. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "sys_perm", ids...) })
  51. codes, err := m.FindAllCodesByProductCode(ctx, productCode)
  52. require.NoError(t, err)
  53. assert.Len(t, codes, 1,
  54. "L-1:只应返回 status=1 的 code;99 不得被误判为启用(那说明 SQL 里不是严格的 `=` ?)")
  55. assert.Equal(t, rows[0].code, codes[0])
  56. }
  57. // TC-0987: DisableNotInCodesWithTx 不得触碰 status≠1 的行。
  58. func TestSysPermModel_L1_DisableNotInCodes_LeavesNonEnabledAlone(t *testing.T) {
  59. ctx := context.Background()
  60. conn := testutil.GetTestSqlConn()
  61. m := newTestSysPermModel(t)
  62. productCode := "l1_dis_" + testutil.UniqueId()
  63. now := time.Now().Unix()
  64. rows := []struct {
  65. code string
  66. status int64
  67. }{
  68. {"k_on_" + testutil.UniqueId(), 1}, // 在白名单,保留
  69. {"k_rm_" + testutil.UniqueId(), 1}, // 不在白名单,会 1→2
  70. {"k_off_" + testutil.UniqueId(), 2}, // 已禁用,不动
  71. {"k_rv_" + testutil.UniqueId(), 99}, // 未来枚举值,不得被误改
  72. }
  73. ids := make([]int64, 0, len(rows))
  74. for _, r := range rows {
  75. res, err := m.Insert(ctx, &perm.SysPerm{
  76. ProductCode: productCode, Name: "n", Code: r.code,
  77. Status: r.status, CreateTime: now, UpdateTime: now,
  78. })
  79. require.NoError(t, err)
  80. id, _ := res.LastInsertId()
  81. ids = append(ids, id)
  82. }
  83. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "sys_perm", ids...) })
  84. var disabled int64
  85. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  86. var e error
  87. disabled, e = m.DisableNotInCodesWithTx(c, session, productCode, []string{rows[0].code}, now)
  88. return e
  89. })
  90. require.NoError(t, err)
  91. assert.Equal(t, int64(1), disabled, "L-1:只有 status=1 且不在白名单的 1 行会被禁用")
  92. // 逐行校验状态。
  93. for i := range rows {
  94. p, err := m.FindOne(ctx, ids[i])
  95. require.NoError(t, err)
  96. switch i {
  97. case 0:
  98. assert.Equal(t, int64(1), p.Status, "白名单内 status=1 必须保留为 1")
  99. case 1:
  100. assert.Equal(t, int64(2), p.Status, "不在白名单 status=1 必须变 2")
  101. case 2:
  102. assert.Equal(t, int64(2), p.Status, "已是 2 的行继续 2")
  103. case 3:
  104. assert.Equal(t, int64(99), p.Status,
  105. "L-1:status=99 不得被 SQL 触及。若变成 2,说明 WHERE 里的 `status=?` 被误写成 `status!=2`")
  106. }
  107. }
  108. }