findMapByProductCodeWithTx_audit_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package perm_test
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "perms-system-server/internal/model/perm"
  7. "perms-system-server/internal/testutil"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. "github.com/zeromicro/go-zero/core/stores/sqlx"
  11. )
  12. // ---------------------------------------------------------------------------
  13. // 覆盖目标:审计 M-6 修复的预留基础设施 —— FindMapByProductCodeWithTx。
  14. // 它目前尚未在 SyncPermsService 的路径里被连起来使用(service.go 的 NOTE 也说明了这一点),
  15. // 但作为供后续 SELECT FOR UPDATE 串行化用的基础方法,必须满足两个契约:
  16. // 1) 必须能在 tx 内跑通,并且返回结果与 tx 外的 FindMapByProductCode 完全一致;
  17. // 2) 当 productCode 没有任何行时,返回 empty map 而不是 nil(便于上层 `_, ok := map[x]` 安全查询)。
  18. // 如果未来有人改这个方法让它忘记填充 map 或返回 nil,这些测试会立即失败,避免 M-6 的串行化路径被悄悄破坏。
  19. // ---------------------------------------------------------------------------
  20. // TC-0807: FindMapByProductCodeWithTx 与 tx 外 FindMapByProductCode 数据一致。
  21. func TestSysPermModel_FindMapByProductCodeWithTx_EqualsNonTx(t *testing.T) {
  22. ctx := context.Background()
  23. m := newTestSysPermModel(t)
  24. conn := testutil.GetTestSqlConn()
  25. productCode := "pc_fmwtx_" + testutil.UniqueId()
  26. now := time.Now().Unix()
  27. res1, err := m.Insert(ctx, &perm.SysPerm{
  28. ProductCode: productCode, Name: "a", Code: "a_" + testutil.UniqueId(),
  29. Status: 1, CreateTime: now, UpdateTime: now,
  30. })
  31. require.NoError(t, err)
  32. id1, _ := res1.LastInsertId()
  33. res2, err := m.Insert(ctx, &perm.SysPerm{
  34. ProductCode: productCode, Name: "b", Code: "b_" + testutil.UniqueId(),
  35. Status: 2, CreateTime: now, UpdateTime: now,
  36. })
  37. require.NoError(t, err)
  38. id2, _ := res2.LastInsertId()
  39. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_perm`", id1, id2) })
  40. nonTx, err := m.FindMapByProductCode(ctx, productCode)
  41. require.NoError(t, err)
  42. require.Len(t, nonTx, 2)
  43. var withTx map[string]*perm.SysPerm
  44. require.NoError(t, m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  45. var err error
  46. withTx, err = m.FindMapByProductCodeWithTx(c, session, productCode)
  47. return err
  48. }))
  49. require.Len(t, withTx, 2)
  50. for code, p := range nonTx {
  51. gotWithTx, ok := withTx[code]
  52. require.True(t, ok, "tx 版本必须返回与非 tx 版本相同的 code 集合")
  53. assert.Equal(t, p.Id, gotWithTx.Id)
  54. assert.Equal(t, p.Status, gotWithTx.Status, "status(尤其是禁用态)必须真实透传,不能被过滤")
  55. assert.Equal(t, p.Name, gotWithTx.Name)
  56. }
  57. }
  58. // TC-0808: 空 productCode 下 FindMapByProductCodeWithTx 返回非 nil 的空 map。
  59. // 上层同步逻辑里会对 map 直接做 `_, ok := existingMap[item.Code]`;如果是 nil 依然安全,
  60. // 但若不慎写成 `existingMap[item.Code] = ...` 就会炸,因此约定为"空 map"更稳。
  61. func TestSysPermModel_FindMapByProductCodeWithTx_EmptyIsNonNil(t *testing.T) {
  62. ctx := context.Background()
  63. m := newTestSysPermModel(t)
  64. productCode := "pc_empty_" + testutil.UniqueId()
  65. var withTx map[string]*perm.SysPerm
  66. require.NoError(t, m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  67. var err error
  68. withTx, err = m.FindMapByProductCodeWithTx(c, session, productCode)
  69. return err
  70. }))
  71. require.NotNil(t, withTx, "空集必须是 empty map,而不是 nil(避免上层误用 map 赋值时 panic)")
  72. assert.Empty(t, withTx)
  73. }