createDeptLogic_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package dept
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "testing"
  7. "time"
  8. deptModel "perms-system-server/internal/model/dept"
  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. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. )
  17. func insertDeptRaw(ctx context.Context, svcCtx *svc.ServiceContext, parentId int64, name, path string) (int64, error) {
  18. now := time.Now().Unix()
  19. result, err := svcCtx.SysDeptModel.Insert(ctx, &deptModel.SysDept{
  20. ParentId: parentId,
  21. Name: name,
  22. Path: path,
  23. Sort: 0,
  24. DeptType: "NORMAL",
  25. Status: 1,
  26. CreateTime: now,
  27. UpdateTime: now,
  28. })
  29. if err != nil {
  30. return 0, err
  31. }
  32. id, _ := result.LastInsertId()
  33. d, err := svcCtx.SysDeptModel.FindOne(ctx, id)
  34. if err != nil {
  35. return id, err
  36. }
  37. d.Path = fmt.Sprintf("%s%d/", path, id)
  38. d.UpdateTime = now
  39. return id, svcCtx.SysDeptModel.Update(ctx, d)
  40. }
  41. // TC-0093: 父部门不存在
  42. func TestCreateDept_ParentNotFound(t *testing.T) {
  43. ctx := ctxhelper.SuperAdminCtx()
  44. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  45. l := NewCreateDeptLogic(ctx, svcCtx)
  46. resp, err := l.CreateDept(&types.CreateDeptReq{
  47. ParentId: 999999999,
  48. Name: "orphan_" + testutil.UniqueId(),
  49. })
  50. assert.Nil(t, resp)
  51. require.Error(t, err)
  52. var ce *response.CodeError
  53. require.True(t, errors.As(err, &ce))
  54. assert.Equal(t, 404, ce.Code())
  55. assert.Contains(t, ce.Error(), "父部门不存在")
  56. }
  57. // TC-0091: 创建顶级部门
  58. func TestCreateDept_TopLevel_ViaRawInsert(t *testing.T) {
  59. ctx := context.Background()
  60. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  61. conn := testutil.GetTestSqlConn()
  62. name := "dept_top_" + testutil.UniqueId()
  63. id, err := insertDeptRaw(ctx, svcCtx, 0, name, "/")
  64. require.NoError(t, err)
  65. require.Greater(t, id, int64(0))
  66. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_dept`", id) })
  67. dept, err := svcCtx.SysDeptModel.FindOne(ctx, id)
  68. require.NoError(t, err)
  69. assert.Equal(t, name, dept.Name)
  70. assert.Equal(t, int64(0), dept.ParentId)
  71. assert.Equal(t, fmt.Sprintf("/%d/", id), dept.Path)
  72. assert.Equal(t, int64(1), dept.Status)
  73. }
  74. // TC-0092: 创建子部门
  75. func TestCreateDept_Child_ViaRawInsert(t *testing.T) {
  76. ctx := context.Background()
  77. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  78. conn := testutil.GetTestSqlConn()
  79. parentId, err := insertDeptRaw(ctx, svcCtx, 0, "par_"+testutil.UniqueId(), "/")
  80. require.NoError(t, err)
  81. parentDept, _ := svcCtx.SysDeptModel.FindOne(ctx, parentId)
  82. childId, err := insertDeptRaw(ctx, svcCtx, parentId, "child_"+testutil.UniqueId(), parentDept.Path)
  83. require.NoError(t, err)
  84. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_dept`", childId, parentId) })
  85. child, err := svcCtx.SysDeptModel.FindOne(ctx, childId)
  86. require.NoError(t, err)
  87. assert.Equal(t, parentId, child.ParentId)
  88. assert.Equal(t, fmt.Sprintf("/%d/%d/", parentId, childId), child.Path)
  89. }
  90. // TC-0099: 多层嵌套(5层)
  91. func TestCreateDept_MultiLevel(t *testing.T) {
  92. ctx := context.Background()
  93. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  94. conn := testutil.GetTestSqlConn()
  95. l1Id, err := insertDeptRaw(ctx, svcCtx, 0, "L1_"+testutil.UniqueId(), "/")
  96. require.NoError(t, err)
  97. l1, _ := svcCtx.SysDeptModel.FindOne(ctx, l1Id)
  98. l2Id, err := insertDeptRaw(ctx, svcCtx, l1Id, "L2_"+testutil.UniqueId(), l1.Path)
  99. require.NoError(t, err)
  100. l2, _ := svcCtx.SysDeptModel.FindOne(ctx, l2Id)
  101. l3Id, err := insertDeptRaw(ctx, svcCtx, l2Id, "L3_"+testutil.UniqueId(), l2.Path)
  102. require.NoError(t, err)
  103. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_dept`", l3Id, l2Id, l1Id) })
  104. d3, err := svcCtx.SysDeptModel.FindOne(ctx, l3Id)
  105. require.NoError(t, err)
  106. assert.Equal(t, fmt.Sprintf("/%d/%d/%d/", l1Id, l2Id, l3Id), d3.Path)
  107. }
  108. // TC-0099: 多层嵌套(5层)
  109. func TestCreateDept_FiveLevelNesting(t *testing.T) {
  110. ctx := context.Background()
  111. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  112. conn := testutil.GetTestSqlConn()
  113. var ids []int64
  114. parentId := int64(0)
  115. parentPath := "/"
  116. for level := 1; level <= 5; level++ {
  117. id, err := insertDeptRaw(ctx, svcCtx, parentId, fmt.Sprintf("L%d_%s", level, testutil.UniqueId()), parentPath)
  118. require.NoError(t, err)
  119. ids = append(ids, id)
  120. dept, err := svcCtx.SysDeptModel.FindOne(ctx, id)
  121. require.NoError(t, err)
  122. parentId = id
  123. parentPath = dept.Path
  124. }
  125. t.Cleanup(func() {
  126. for i := len(ids) - 1; i >= 0; i-- {
  127. testutil.CleanTable(ctx, conn, "`sys_dept`", ids[i])
  128. }
  129. })
  130. deepest, err := svcCtx.SysDeptModel.FindOne(ctx, ids[4])
  131. require.NoError(t, err)
  132. expected := fmt.Sprintf("/%d/%d/%d/%d/%d/", ids[0], ids[1], ids[2], ids[3], ids[4])
  133. assert.Equal(t, expected, deepest.Path)
  134. }
  135. // TC-0094: 不传DeptType默认NORMAL
  136. func TestCreateDept_DefaultDeptType(t *testing.T) {
  137. ctx := ctxhelper.SuperAdminCtx()
  138. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  139. conn := testutil.GetTestSqlConn()
  140. l := NewCreateDeptLogic(ctx, svcCtx)
  141. resp, err := l.CreateDept(&types.CreateDeptReq{
  142. ParentId: 0,
  143. Name: "deftype_" + testutil.UniqueId(),
  144. })
  145. require.NoError(t, err)
  146. require.NotNil(t, resp)
  147. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_dept`", resp.Id) })
  148. d, err := svcCtx.SysDeptModel.FindOne(ctx, resp.Id)
  149. require.NoError(t, err)
  150. assert.Equal(t, "NORMAL", d.DeptType)
  151. assert.Contains(t, d.Path, fmt.Sprintf("/%d/", resp.Id))
  152. }
  153. // TC-0095: 传DeptType=DEV
  154. func TestCreateDept_DevDeptType(t *testing.T) {
  155. ctx := ctxhelper.SuperAdminCtx()
  156. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  157. conn := testutil.GetTestSqlConn()
  158. l := NewCreateDeptLogic(ctx, svcCtx)
  159. resp, err := l.CreateDept(&types.CreateDeptReq{
  160. ParentId: 0,
  161. Name: "devtype_" + testutil.UniqueId(),
  162. DeptType: "DEV",
  163. })
  164. require.NoError(t, err)
  165. require.NotNil(t, resp)
  166. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_dept`", resp.Id) })
  167. d, err := svcCtx.SysDeptModel.FindOne(ctx, resp.Id)
  168. require.NoError(t, err)
  169. assert.Equal(t, "DEV", d.DeptType)
  170. assert.Contains(t, d.Path, fmt.Sprintf("/%d/", resp.Id))
  171. }
  172. // TC-0100: 通过Logic创建+验证Path
  173. func TestCreateDept_ViaLogic_PathCorrect(t *testing.T) {
  174. ctx := ctxhelper.SuperAdminCtx()
  175. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  176. conn := testutil.GetTestSqlConn()
  177. l := NewCreateDeptLogic(ctx, svcCtx)
  178. parentResp, err := l.CreateDept(&types.CreateDeptReq{
  179. ParentId: 0,
  180. Name: "parent_" + testutil.UniqueId(),
  181. })
  182. require.NoError(t, err)
  183. childResp, err := l.CreateDept(&types.CreateDeptReq{
  184. ParentId: parentResp.Id,
  185. Name: "child_" + testutil.UniqueId(),
  186. })
  187. require.NoError(t, err)
  188. t.Cleanup(func() {
  189. testutil.CleanTable(ctx, conn, "`sys_dept`", childResp.Id, parentResp.Id)
  190. })
  191. parent, err := svcCtx.SysDeptModel.FindOne(ctx, parentResp.Id)
  192. require.NoError(t, err)
  193. assert.Equal(t, fmt.Sprintf("/%d/", parentResp.Id), parent.Path)
  194. child, err := svcCtx.SysDeptModel.FindOne(ctx, childResp.Id)
  195. require.NoError(t, err)
  196. assert.Equal(t, fmt.Sprintf("/%d/%d/", parentResp.Id, childResp.Id), child.Path)
  197. }
  198. // TC-0532: createDept非超管拒绝
  199. func TestCreateDept_NonSuperAdminRejected(t *testing.T) {
  200. ctx := ctxhelper.AdminCtx("test_product")
  201. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  202. l := NewCreateDeptLogic(ctx, svcCtx)
  203. _, err := l.CreateDept(&types.CreateDeptReq{Name: "test", Sort: 1})
  204. require.Error(t, err)
  205. var ce *response.CodeError
  206. require.True(t, errors.As(err, &ce))
  207. assert.Equal(t, 403, ce.Code())
  208. }
  209. var _ = deptModel.ErrNotFound