addMemberLogic_test.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package member
  2. import (
  3. "database/sql"
  4. "sync"
  5. "testing"
  6. "time"
  7. productModel "perms-system-server/internal/model/product"
  8. memberModel "perms-system-server/internal/model/productmember"
  9. userModel "perms-system-server/internal/model/user"
  10. "perms-system-server/internal/response"
  11. "perms-system-server/internal/svc"
  12. "perms-system-server/internal/testutil"
  13. "perms-system-server/internal/testutil/ctxhelper"
  14. "perms-system-server/internal/types"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. // TC-0146: 正常添加
  19. func TestAddMember_Normal(t *testing.T) {
  20. ctx := ctxhelper.SuperAdminCtx()
  21. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  22. conn := testutil.GetTestSqlConn()
  23. now := time.Now().Unix()
  24. uid := testutil.UniqueId()
  25. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  26. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "s1",
  27. Status: 1, CreateTime: now, UpdateTime: now,
  28. })
  29. require.NoError(t, err)
  30. pId, _ := pRes.LastInsertId()
  31. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  32. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  33. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  34. Status: 1, CreateTime: now, UpdateTime: now,
  35. })
  36. require.NoError(t, err)
  37. uId, _ := uRes.LastInsertId()
  38. t.Cleanup(func() {
  39. testutil.CleanTableByField(ctx, conn, "`sys_product_member`", "productCode", uid)
  40. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  41. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  42. })
  43. logic := NewAddMemberLogic(ctx, svcCtx)
  44. resp, err := logic.AddMember(&types.AddMemberReq{
  45. ProductCode: uid,
  46. UserId: uId,
  47. MemberType: "MEMBER",
  48. })
  49. require.NoError(t, err)
  50. assert.True(t, resp.Id > 0)
  51. member, err := svcCtx.SysProductMemberModel.FindOne(ctx, resp.Id)
  52. require.NoError(t, err)
  53. assert.Equal(t, uid, member.ProductCode)
  54. assert.Equal(t, uId, member.UserId)
  55. assert.Equal(t, "MEMBER", member.MemberType)
  56. assert.Equal(t, int64(1), member.Status)
  57. }
  58. // TC-0147: 产品不存在
  59. func TestAddMember_ProductNotFound(t *testing.T) {
  60. ctx := ctxhelper.SuperAdminCtx()
  61. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  62. logic := NewAddMemberLogic(ctx, svcCtx)
  63. _, err := logic.AddMember(&types.AddMemberReq{
  64. ProductCode: "nonexistent_product_xyz",
  65. UserId: 1,
  66. MemberType: "MEMBER",
  67. })
  68. require.Error(t, err)
  69. ce, ok := err.(*response.CodeError)
  70. require.True(t, ok)
  71. assert.Equal(t, 404, ce.Code())
  72. assert.Equal(t, "产品不存在", ce.Error())
  73. }
  74. // TC-0148: 用户不存在
  75. func TestAddMember_UserNotFound(t *testing.T) {
  76. ctx := ctxhelper.SuperAdminCtx()
  77. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  78. conn := testutil.GetTestSqlConn()
  79. now := time.Now().Unix()
  80. uid := testutil.UniqueId()
  81. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  82. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "s1",
  83. Status: 1, CreateTime: now, UpdateTime: now,
  84. })
  85. require.NoError(t, err)
  86. pId, _ := pRes.LastInsertId()
  87. t.Cleanup(func() {
  88. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  89. })
  90. logic := NewAddMemberLogic(ctx, svcCtx)
  91. _, err = logic.AddMember(&types.AddMemberReq{
  92. ProductCode: uid,
  93. UserId: 999999999,
  94. MemberType: "MEMBER",
  95. })
  96. require.Error(t, err)
  97. ce, ok := err.(*response.CodeError)
  98. require.True(t, ok)
  99. assert.Equal(t, 404, ce.Code())
  100. assert.Equal(t, "用户不存在", ce.Error())
  101. }
  102. // TC-0149: 已是成员
  103. func TestAddMember_AlreadyMember(t *testing.T) {
  104. ctx := ctxhelper.SuperAdminCtx()
  105. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  106. conn := testutil.GetTestSqlConn()
  107. now := time.Now().Unix()
  108. uid := testutil.UniqueId()
  109. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  110. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "s1",
  111. Status: 1, CreateTime: now, UpdateTime: now,
  112. })
  113. require.NoError(t, err)
  114. pId, _ := pRes.LastInsertId()
  115. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  116. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  117. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  118. Status: 1, CreateTime: now, UpdateTime: now,
  119. })
  120. require.NoError(t, err)
  121. uId, _ := uRes.LastInsertId()
  122. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  123. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  124. Status: 1, CreateTime: now, UpdateTime: now,
  125. })
  126. require.NoError(t, err)
  127. mId, _ := mRes.LastInsertId()
  128. t.Cleanup(func() {
  129. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  130. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  131. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  132. })
  133. logic := NewAddMemberLogic(ctx, svcCtx)
  134. _, err = logic.AddMember(&types.AddMemberReq{
  135. ProductCode: uid,
  136. UserId: uId,
  137. MemberType: "ADMIN",
  138. })
  139. require.Error(t, err)
  140. ce, ok := err.(*response.CodeError)
  141. require.True(t, ok)
  142. assert.Equal(t, 409, ce.Code())
  143. assert.Equal(t, "该用户已是该产品成员", ce.Error())
  144. }
  145. // TC-0150: 并发添加
  146. func TestAddMember_ConcurrentSameUserProduct(t *testing.T) {
  147. ctx := ctxhelper.SuperAdminCtx()
  148. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  149. conn := testutil.GetTestSqlConn()
  150. now := time.Now().Unix()
  151. uid := testutil.UniqueId()
  152. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  153. Code: uid, Name: "concurrent_prod", AppKey: uid, AppSecret: "s1",
  154. Status: 1, CreateTime: now, UpdateTime: now,
  155. })
  156. require.NoError(t, err)
  157. pId, _ := pRes.LastInsertId()
  158. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  159. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  160. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  161. Status: 1, CreateTime: now, UpdateTime: now,
  162. })
  163. require.NoError(t, err)
  164. uId, _ := uRes.LastInsertId()
  165. t.Cleanup(func() {
  166. testutil.CleanTableByField(ctx, conn, "`sys_product_member`", "productCode", uid)
  167. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  168. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  169. })
  170. var wg sync.WaitGroup
  171. results := make(chan error, 2)
  172. for i := 0; i < 2; i++ {
  173. wg.Add(1)
  174. go func() {
  175. defer wg.Done()
  176. logic := NewAddMemberLogic(ctx, svcCtx)
  177. _, err := logic.AddMember(&types.AddMemberReq{
  178. ProductCode: uid,
  179. UserId: uId,
  180. MemberType: "MEMBER",
  181. })
  182. results <- err
  183. }()
  184. }
  185. wg.Wait()
  186. close(results)
  187. var errs []error
  188. for e := range results {
  189. errs = append(errs, e)
  190. }
  191. require.Len(t, errs, 2)
  192. successCount := 0
  193. failCount := 0
  194. for _, e := range errs {
  195. if e == nil {
  196. successCount++
  197. } else {
  198. failCount++
  199. }
  200. }
  201. assert.Equal(t, 1, successCount, "exactly one goroutine should succeed")
  202. assert.Equal(t, 1, failCount, "exactly one goroutine should fail (409 or DB duplicate)")
  203. }