package perm_test import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/core/stores/sqlx" "perms-system-server/internal/model/perm" "perms-system-server/internal/testutil" ) // --------------------------------------------------------------------------- // 审计 L-1(第 8 轮)—— FindAllCodesByProductCode / DisableNotInCodesWithTx 的 // `status = ?` 必须是真正的参数占位符,而不是 fmt.Sprintf("%d") 回填。 // // 测试策略:往同一 productCode 里塞 status ∈ {1, 2, 99} 三类行(99 模拟未来枚举值, // 例如 "审核中"),断言: // - FindAllCodesByProductCode 只返回 status=1 的 code,不会把 99 误解成"非零即启用"。 // - DisableNotInCodesWithTx 只影响 status=1 → 2 的跃迁,不得触碰 status=99。 // 如果回退成 "WHERE status = 1" 的 Sprintf 版本,这两个断言仍会过;所以额外追加: // - 用"空白不在白名单"的 DisableNotInCodesWithTx(codes=nil 分支)二次验证只禁用 // 已启用行,不扫到 status=99;这一条专门防御未来有人把 consts.StatusEnabled 的 // 类型改成 int8/枚举时,%d 变成 "%d(1)" 之类退化字面量。 // --------------------------------------------------------------------------- // TC-0986: 非 {1,2} 的未来扩展状态必须被过滤掉;只认 status=1 为 enabled。 func TestSysPermModel_L1_FindAllCodes_StrictlyEqualEnabled(t *testing.T) { ctx := context.Background() conn := testutil.GetTestSqlConn() m := newTestSysPermModel(t) productCode := "l1_strict_" + testutil.UniqueId() now := time.Now().Unix() rows := []struct { code string status int64 }{ {"ena_" + testutil.UniqueId(), 1}, {"dis_" + testutil.UniqueId(), 2}, {"rev_" + testutil.UniqueId(), 99}, } ids := make([]int64, 0, len(rows)) for _, r := range rows { res, err := m.Insert(ctx, &perm.SysPerm{ ProductCode: productCode, Name: "n", Code: r.code, Status: r.status, CreateTime: now, UpdateTime: now, }) require.NoError(t, err) id, _ := res.LastInsertId() ids = append(ids, id) } t.Cleanup(func() { testutil.CleanTable(ctx, conn, "sys_perm", ids...) }) codes, err := m.FindAllCodesByProductCode(ctx, productCode) require.NoError(t, err) assert.Len(t, codes, 1, "L-1:只应返回 status=1 的 code;99 不得被误判为启用(那说明 SQL 里不是严格的 `=` ?)") assert.Equal(t, rows[0].code, codes[0]) } // TC-0987: DisableNotInCodesWithTx 不得触碰 status≠1 的行。 func TestSysPermModel_L1_DisableNotInCodes_LeavesNonEnabledAlone(t *testing.T) { ctx := context.Background() conn := testutil.GetTestSqlConn() m := newTestSysPermModel(t) productCode := "l1_dis_" + testutil.UniqueId() now := time.Now().Unix() rows := []struct { code string status int64 }{ {"k_on_" + testutil.UniqueId(), 1}, // 在白名单,保留 {"k_rm_" + testutil.UniqueId(), 1}, // 不在白名单,会 1→2 {"k_off_" + testutil.UniqueId(), 2}, // 已禁用,不动 {"k_rv_" + testutil.UniqueId(), 99}, // 未来枚举值,不得被误改 } ids := make([]int64, 0, len(rows)) for _, r := range rows { res, err := m.Insert(ctx, &perm.SysPerm{ ProductCode: productCode, Name: "n", Code: r.code, Status: r.status, CreateTime: now, UpdateTime: now, }) require.NoError(t, err) id, _ := res.LastInsertId() ids = append(ids, id) } t.Cleanup(func() { testutil.CleanTable(ctx, conn, "sys_perm", ids...) }) var disabled int64 err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error { var e error disabled, e = m.DisableNotInCodesWithTx(c, session, productCode, []string{rows[0].code}, now) return e }) require.NoError(t, err) assert.Equal(t, int64(1), disabled, "L-1:只有 status=1 且不在白名单的 1 行会被禁用") // 逐行校验状态。 for i := range rows { p, err := m.FindOne(ctx, ids[i]) require.NoError(t, err) switch i { case 0: assert.Equal(t, int64(1), p.Status, "白名单内 status=1 必须保留为 1") case 1: assert.Equal(t, int64(2), p.Status, "不在白名单 status=1 必须变 2") case 2: assert.Equal(t, int64(2), p.Status, "已是 2 的行继续 2") case 3: assert.Equal(t, int64(99), p.Status, "L-1:status=99 不得被 SQL 触及。若变成 2,说明 WHERE 里的 `status=?` 被误写成 `status!=2`") } } }