roleDetailLogic_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package role
  2. import (
  3. "errors"
  4. "github.com/stretchr/testify/assert"
  5. "github.com/stretchr/testify/require"
  6. permModel "perms-system-server/internal/model/perm"
  7. roleModel "perms-system-server/internal/model/role"
  8. "perms-system-server/internal/model/roleperm"
  9. "perms-system-server/internal/response"
  10. "perms-system-server/internal/svc"
  11. "perms-system-server/internal/testutil"
  12. "perms-system-server/internal/testutil/ctxhelper"
  13. "perms-system-server/internal/types"
  14. "testing"
  15. "time"
  16. )
  17. func TestRoleDetail_Normal(t *testing.T) {
  18. ctx := ctxhelper.SuperAdminCtx()
  19. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  20. conn := testutil.GetTestSqlConn()
  21. now := time.Now().Unix()
  22. pc := testutil.UniqueId()
  23. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  24. ProductCode: pc, Name: testutil.UniqueId(), Remark: "detail test",
  25. Status: 1, PermsLevel: 1, CreateTime: now, UpdateTime: now,
  26. })
  27. require.NoError(t, err)
  28. roleId, _ := roleRes.LastInsertId()
  29. p1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  30. ProductCode: pc, Name: testutil.UniqueId(), Code: testutil.UniqueId(),
  31. Status: 1, CreateTime: now, UpdateTime: now,
  32. })
  33. require.NoError(t, err)
  34. p1Id, _ := p1Res.LastInsertId()
  35. p2Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  36. ProductCode: pc, Name: testutil.UniqueId(), Code: testutil.UniqueId(),
  37. Status: 1, CreateTime: now, UpdateTime: now,
  38. })
  39. require.NoError(t, err)
  40. p2Id, _ := p2Res.LastInsertId()
  41. rp1Res, err := svcCtx.SysRolePermModel.Insert(ctx, &roleperm.SysRolePerm{
  42. RoleId: roleId, PermId: p1Id, CreateTime: now, UpdateTime: now,
  43. })
  44. require.NoError(t, err)
  45. rp1Id, _ := rp1Res.LastInsertId()
  46. rp2Res, err := svcCtx.SysRolePermModel.Insert(ctx, &roleperm.SysRolePerm{
  47. RoleId: roleId, PermId: p2Id, CreateTime: now, UpdateTime: now,
  48. })
  49. require.NoError(t, err)
  50. rp2Id, _ := rp2Res.LastInsertId()
  51. t.Cleanup(func() {
  52. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rp1Id, rp2Id)
  53. testutil.CleanTable(ctx, conn, "`sys_perm`", p1Id, p2Id)
  54. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  55. })
  56. logic := NewRoleDetailLogic(ctx, svcCtx)
  57. resp, err := logic.RoleDetail(&types.RoleDetailReq{Id: roleId})
  58. require.NoError(t, err)
  59. assert.Equal(t, roleId, resp.Id)
  60. assert.Equal(t, pc, resp.ProductCode)
  61. assert.Equal(t, "detail test", resp.Remark)
  62. assert.ElementsMatch(t, []int64{p1Id, p2Id}, resp.PermIds)
  63. }
  64. // TC-0125: 不存在
  65. func TestRoleDetail_NotFound(t *testing.T) {
  66. ctx := ctxhelper.SuperAdminCtx()
  67. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  68. logic := NewRoleDetailLogic(ctx, svcCtx)
  69. resp, err := logic.RoleDetail(&types.RoleDetailReq{Id: 999999999})
  70. assert.Nil(t, resp)
  71. require.Error(t, err)
  72. var ce *response.CodeError
  73. require.True(t, errors.As(err, &ce))
  74. assert.Equal(t, 404, ce.Code())
  75. assert.Equal(t, "角色不存在", ce.Error())
  76. }
  77. func TestRoleDetail_MN3_CrossProductReturns404NotFound(t *testing.T) {
  78. ctx := ctxhelper.SuperAdminCtx()
  79. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  80. conn := testutil.GetTestSqlConn()
  81. now := time.Now().Unix()
  82. // 插入别的产品("test_product2")下的 role
  83. otherProduct := "mn3_other_" + testutil.UniqueId()
  84. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  85. ProductCode: otherProduct, Name: "mn3_role_" + testutil.UniqueId(),
  86. Remark: "mn3", Status: 1, PermsLevel: 1, CreateTime: now, UpdateTime: now,
  87. })
  88. require.NoError(t, err)
  89. roleId, _ := roleRes.LastInsertId()
  90. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_role`", roleId) })
  91. // Admin 身份在 "test_product" 下访问 "mn3_other_*" 的 roleId
  92. adminCtx := ctxhelper.AdminCtx("test_product")
  93. resp, err := NewRoleDetailLogic(adminCtx, svcCtx).RoleDetail(&types.RoleDetailReq{Id: roleId})
  94. assert.Nil(t, resp)
  95. require.Error(t, err)
  96. var ce *response.CodeError
  97. require.True(t, errors.As(err, &ce))
  98. assert.Equal(t, 404, ce.Code(),
  99. "跨产品访问必须 404,不得以 403 暴露存在性")
  100. assert.Equal(t, "角色不存在", ce.Error(),
  101. "响应文案必须与 'id 真实不存在' 完全一致,彻底关闭枚举 oracle")
  102. }
  103. // TC-1001: 对照 —— "id 不存在" 的响应必须与 "跨产品访问" 完全一致(code 与 body)。
  104. func TestRoleDetail_MN3_NotFoundAndCrossProduct_Indistinguishable(t *testing.T) {
  105. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  106. conn := testutil.GetTestSqlConn()
  107. ctx := ctxhelper.SuperAdminCtx()
  108. now := time.Now().Unix()
  109. // 预埋一条别的产品的角色
  110. otherProduct := "mn3_cmp_" + testutil.UniqueId()
  111. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  112. ProductCode: otherProduct, Name: "mn3cmp_" + testutil.UniqueId(),
  113. Remark: "", Status: 1, PermsLevel: 1, CreateTime: now, UpdateTime: now,
  114. })
  115. require.NoError(t, err)
  116. existingId, _ := roleRes.LastInsertId()
  117. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_role`", existingId) })
  118. adminCtx := ctxhelper.AdminCtx("test_product")
  119. // (A) 跨产品访问真实存在的 id
  120. _, errCross := NewRoleDetailLogic(adminCtx, svcCtx).RoleDetail(&types.RoleDetailReq{Id: existingId})
  121. require.Error(t, errCross)
  122. var ceA *response.CodeError
  123. require.True(t, errors.As(errCross, &ceA))
  124. // (B) 访问一个肯定不存在的 id(id 选在 existingId + 很大偏移,规避数据库递增到该值)
  125. _, errAbsent := NewRoleDetailLogic(adminCtx, svcCtx).RoleDetail(
  126. &types.RoleDetailReq{Id: existingId + 999_999_999},
  127. )
  128. require.Error(t, errAbsent)
  129. var ceB *response.CodeError
  130. require.True(t, errors.As(errAbsent, &ceB))
  131. // 响应码与文案必须完全一致,不给任何侧信道
  132. assert.Equal(t, ceB.Code(), ceA.Code(),
  133. "跨产品 vs id 不存在必须返回相同 code")
  134. assert.Equal(t, ceB.Error(), ceA.Error(),
  135. "跨产品 vs id 不存在必须返回相同 body")
  136. }
  137. // TC-1002: 超管跨产品仍然可以正常访问(/运维路径不能被误伤)。
  138. func TestRoleDetail_MN3_SuperAdminCanStillAccessCrossProduct(t *testing.T) {
  139. ctx := ctxhelper.SuperAdminCtx()
  140. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  141. conn := testutil.GetTestSqlConn()
  142. now := time.Now().Unix()
  143. otherProduct := "mn3_sa_" + testutil.UniqueId()
  144. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  145. ProductCode: otherProduct, Name: "mn3sa_" + testutil.UniqueId(),
  146. Remark: "sa_cross", Status: 1, PermsLevel: 1, CreateTime: now, UpdateTime: now,
  147. })
  148. require.NoError(t, err)
  149. roleId, _ := roleRes.LastInsertId()
  150. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  151. ProductCode: otherProduct, Name: "mn3sa_p_" + testutil.UniqueId(), Code: testutil.UniqueId(),
  152. Status: 1, CreateTime: now, UpdateTime: now,
  153. })
  154. require.NoError(t, err)
  155. permId, _ := permRes.LastInsertId()
  156. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &roleperm.SysRolePerm{
  157. RoleId: roleId, PermId: permId, CreateTime: now, UpdateTime: now,
  158. })
  159. require.NoError(t, err)
  160. rpId, _ := rpRes.LastInsertId()
  161. t.Cleanup(func() {
  162. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  163. testutil.CleanTable(ctx, conn, "`sys_perm`", permId)
  164. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  165. })
  166. // 超管在 "test_product" 当前身份,但跨产品访问 "mn3_sa_*" 的 role,应允许
  167. resp, err := NewRoleDetailLogic(ctx, svcCtx).RoleDetail(&types.RoleDetailReq{Id: roleId})
  168. require.NoError(t, err, "超管必须能跨产品查看 role,支撑/运维路径")
  169. require.NotNil(t, resp)
  170. assert.Equal(t, roleId, resp.Id)
  171. assert.Equal(t, otherProduct, resp.ProductCode)
  172. assert.Contains(t, resp.PermIds, permId)
  173. }