sysProductMemberModel_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. package productmember
  2. import (
  3. "context"
  4. "errors"
  5. "math/rand"
  6. "testing"
  7. "time"
  8. "perms-system-server/internal/testutil"
  9. "github.com/go-sql-driver/mysql"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. "github.com/zeromicro/go-zero/core/stores/sqlx"
  13. )
  14. func randProductMemberUserId() int64 {
  15. return int64(900000 + rand.Intn(100000))
  16. }
  17. // TC-0310: 正常插入
  18. func TestSysProductMemberModel_CRUD(t *testing.T) {
  19. ctx := context.Background()
  20. conn := testutil.GetTestSqlConn()
  21. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  22. pc := "t_pm_" + testutil.UniqueId()
  23. userId := randProductMemberUserId()
  24. ts := time.Now().Unix()
  25. data := &SysProductMember{
  26. ProductCode: pc,
  27. UserId: userId,
  28. MemberType: "MEMBER",
  29. Status: 1,
  30. CreateTime: ts,
  31. UpdateTime: ts,
  32. }
  33. res, err := m.Insert(ctx, data)
  34. if err != nil {
  35. t.Fatalf("Insert: %v", err)
  36. }
  37. id, err := res.LastInsertId()
  38. if err != nil {
  39. t.Fatalf("LastInsertId: %v", err)
  40. }
  41. defer testutil.CleanTable(ctx, conn, "sys_product_member", id)
  42. got, err := m.FindOne(ctx, id)
  43. if err != nil {
  44. t.Fatalf("FindOne: %v", err)
  45. }
  46. if got.ProductCode != pc || got.UserId != userId {
  47. t.Fatalf("FindOne mismatch: %+v", got)
  48. }
  49. byPair, err := m.FindOneByProductCodeUserId(ctx, pc, userId)
  50. if err != nil {
  51. t.Fatalf("FindOneByProductCodeUserId: %v", err)
  52. }
  53. if byPair.Id != id {
  54. t.Fatalf("FindOneByProductCodeUserId id want %d got %d", id, byPair.Id)
  55. }
  56. newTs := ts + 1
  57. got.Status = 2
  58. got.UpdateTime = newTs
  59. if err := m.Update(ctx, got); err != nil {
  60. t.Fatalf("Update: %v", err)
  61. }
  62. updated, err := m.FindOne(ctx, id)
  63. if err != nil {
  64. t.Fatalf("FindOne after update: %v", err)
  65. }
  66. if updated.Status != 2 || updated.UpdateTime != newTs {
  67. t.Fatalf("after Update: %+v", updated)
  68. }
  69. if err := m.Delete(ctx, id); err != nil {
  70. t.Fatalf("Delete: %v", err)
  71. }
  72. if _, err := m.FindOne(ctx, id); err != ErrNotFound {
  73. t.Fatalf("after Delete want ErrNotFound got %v", err)
  74. }
  75. }
  76. // TC-0475: 正常分页
  77. func TestSysProductMemberModel_FindListByProductCode(t *testing.T) {
  78. ctx := context.Background()
  79. conn := testutil.GetTestSqlConn()
  80. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  81. pc := "t_pm_page_" + testutil.UniqueId()
  82. ts := time.Now().Unix()
  83. var ids []int64
  84. for i := 0; i < 5; i++ {
  85. res, err := m.Insert(ctx, &SysProductMember{
  86. ProductCode: pc,
  87. UserId: randProductMemberUserId(),
  88. MemberType: "MEMBER",
  89. Status: 1,
  90. CreateTime: ts,
  91. UpdateTime: ts,
  92. })
  93. if err != nil {
  94. t.Fatalf("Insert: %v", err)
  95. }
  96. id, _ := res.LastInsertId()
  97. ids = append(ids, id)
  98. }
  99. defer func() {
  100. for _, id := range ids {
  101. testutil.CleanTable(ctx, conn, "sys_product_member", id)
  102. }
  103. }()
  104. list, total, err := m.FindListByProductCode(ctx, pc, 1, 2)
  105. if err != nil {
  106. t.Fatalf("page1: %v", err)
  107. }
  108. if total != 5 || len(list) != 2 {
  109. t.Fatalf("page1 total=%d len=%d", total, len(list))
  110. }
  111. list2, total2, err := m.FindListByProductCode(ctx, pc, 2, 2)
  112. if err != nil {
  113. t.Fatalf("page2: %v", err)
  114. }
  115. if total2 != 5 || len(list2) != 2 {
  116. t.Fatalf("page2 total=%d len=%d", total2, len(list2))
  117. }
  118. list3, total3, err := m.FindListByProductCode(ctx, pc, 3, 2)
  119. if err != nil {
  120. t.Fatalf("page3: %v", err)
  121. }
  122. if total3 != 5 || len(list3) != 1 {
  123. t.Fatalf("page3 total=%d len=%d", total3, len(list3))
  124. }
  125. }
  126. // TC-0477: [REMOVED] FindMapByProductCodeUserIds 作为僵尸接口已在 L-5 审计中被剥离;
  127. // 上层 UserListLogic 改走 FindListByProductMembers 合并查询(见 mock 测试注释)。
  128. // 这里保留 stub 以保持 TC 编号可追溯。
  129. // TC-0336: 多条记录(3条)
  130. func TestSysProductMemberModel_BatchInsert(t *testing.T) {
  131. ctx := context.Background()
  132. conn := testutil.GetTestSqlConn()
  133. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  134. pc := "t_pm_bi_" + testutil.UniqueId()
  135. u1, u2 := randProductMemberUserId(), randProductMemberUserId()
  136. ts := time.Now().Unix()
  137. list := []*SysProductMember{
  138. {Id: 930000001, ProductCode: pc, UserId: u1, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts},
  139. {Id: 930000002, ProductCode: pc, UserId: u2, MemberType: "ADMIN", Status: 1, CreateTime: ts, UpdateTime: ts},
  140. }
  141. if err := m.BatchInsert(ctx, list); err != nil {
  142. t.Fatalf("BatchInsert: %v", err)
  143. }
  144. var rows []struct {
  145. Id int64 `db:"id"`
  146. }
  147. q := "SELECT `id` FROM `sys_product_member` WHERE `productCode` = ? ORDER BY `id`"
  148. if err := conn.QueryRowsCtx(ctx, &rows, q, pc); err != nil {
  149. t.Fatalf("query: %v", err)
  150. }
  151. defer func() {
  152. for _, r := range rows {
  153. testutil.CleanTable(ctx, conn, "sys_product_member", r.Id)
  154. }
  155. }()
  156. if len(rows) != 2 {
  157. t.Fatalf("want 2 rows got %d", len(rows))
  158. }
  159. }
  160. // TC-0312: 唯一索引冲突
  161. func TestSysProductMemberModel_DuplicateConstraint(t *testing.T) {
  162. ctx := context.Background()
  163. conn := testutil.GetTestSqlConn()
  164. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  165. pc := "t_pm_dup_" + testutil.UniqueId()
  166. userId := randProductMemberUserId()
  167. ts := time.Now().Unix()
  168. res, err := m.Insert(ctx, &SysProductMember{ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts})
  169. if err != nil {
  170. t.Fatalf("Insert: %v", err)
  171. }
  172. id, _ := res.LastInsertId()
  173. defer testutil.CleanTable(ctx, conn, "sys_product_member", id)
  174. _, err = m.Insert(ctx, &SysProductMember{ProductCode: pc, UserId: userId, MemberType: "ADMIN", Status: 1, CreateTime: ts, UpdateTime: ts})
  175. if err == nil {
  176. t.Fatal("second Insert want error")
  177. }
  178. var me *mysql.MySQLError
  179. if !errors.As(err, &me) || me.Number != 1062 {
  180. t.Fatalf("want duplicate key 1062, got %v", err)
  181. }
  182. }
  183. // TC-0319: 记录不存在
  184. func TestSysProductMemberModel_FindOne_NotFound(t *testing.T) {
  185. conn := testutil.GetTestSqlConn()
  186. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  187. _, err := m.FindOne(context.Background(), 999999999999)
  188. if err != ErrNotFound {
  189. t.Fatalf("want ErrNotFound got %v", err)
  190. }
  191. }
  192. // TC-0392: FindOneByProductCodeUserId
  193. func TestSysProductMemberModel_FindOneByProductCodeUserId_NotFound(t *testing.T) {
  194. conn := testutil.GetTestSqlConn()
  195. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  196. _, err := m.FindOneByProductCodeUserId(context.Background(), "notexist_"+testutil.UniqueId(), 999999999)
  197. if err != ErrNotFound {
  198. t.Fatalf("want ErrNotFound got %v", err)
  199. }
  200. }
  201. // TC-0476: 空结果
  202. func TestSysProductMemberModel_FindListByProductCode_Empty(t *testing.T) {
  203. conn := testutil.GetTestSqlConn()
  204. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  205. list, total, err := m.FindListByProductCode(context.Background(), "empty_"+testutil.UniqueId(), 1, 10)
  206. if err != nil {
  207. t.Fatalf("err: %v", err)
  208. }
  209. if total != 0 || len(list) != 0 {
  210. t.Fatalf("want empty got total=%d len=%d", total, len(list))
  211. }
  212. }
  213. // TC-0334: 空列表
  214. func TestSysProductMemberModel_BatchInsert_Empty(t *testing.T) {
  215. conn := testutil.GetTestSqlConn()
  216. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  217. if err := m.BatchInsert(context.Background(), nil); err != nil {
  218. t.Fatalf("nil: %v", err)
  219. }
  220. if err := m.BatchInsert(context.Background(), []*SysProductMember{}); err != nil {
  221. t.Fatalf("empty: %v", err)
  222. }
  223. }
  224. // TC-0353: 空ids
  225. func TestSysProductMemberModel_BatchDelete_Empty(t *testing.T) {
  226. conn := testutil.GetTestSqlConn()
  227. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  228. if err := m.BatchDelete(context.Background(), nil); err != nil {
  229. t.Fatalf("nil: %v", err)
  230. }
  231. if err := m.BatchDelete(context.Background(), []int64{}); err != nil {
  232. t.Fatalf("empty: %v", err)
  233. }
  234. }
  235. // TC-0314: 事务内插入
  236. func TestSysProductMemberModel_InsertWithTx_Normal(t *testing.T) {
  237. ctx := context.Background()
  238. conn := testutil.GetTestSqlConn()
  239. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  240. pc := "t_pm_itx_" + testutil.UniqueId()
  241. userId := randProductMemberUserId()
  242. ts := time.Now().Unix()
  243. var insertedId int64
  244. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  245. res, err := m.InsertWithTx(c, session, &SysProductMember{
  246. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  247. })
  248. if err != nil {
  249. return err
  250. }
  251. insertedId, _ = res.LastInsertId()
  252. return nil
  253. })
  254. if err != nil {
  255. t.Fatalf("TransactCtx: %v", err)
  256. }
  257. defer testutil.CleanTable(ctx, conn, "sys_product_member", insertedId)
  258. got, err := m.FindOne(ctx, insertedId)
  259. if err != nil {
  260. t.Fatalf("FindOne: %v", err)
  261. }
  262. if got.ProductCode != pc || got.UserId != userId {
  263. t.Fatalf("mismatch: %+v", got)
  264. }
  265. }
  266. // TC-0316: 事务回滚后无数据
  267. func TestSysProductMemberModel_InsertWithTx_Rollback(t *testing.T) {
  268. ctx := context.Background()
  269. conn := testutil.GetTestSqlConn()
  270. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  271. pc := "t_pm_irb_" + testutil.UniqueId()
  272. userId := randProductMemberUserId()
  273. ts := time.Now().Unix()
  274. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  275. _, err := m.InsertWithTx(c, session, &SysProductMember{
  276. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  277. })
  278. if err != nil {
  279. return err
  280. }
  281. return errors.New("rollback")
  282. })
  283. if err == nil || err.Error() != "rollback" {
  284. t.Fatalf("want rollback error got %v", err)
  285. }
  286. _, err = m.FindOneByProductCodeUserId(ctx, pc, userId)
  287. if err != ErrNotFound {
  288. t.Fatalf("after rollback want ErrNotFound got %v", err)
  289. }
  290. }
  291. // TC-0326: 记录不存在
  292. func TestSysProductMemberModel_Update_NotFound(t *testing.T) {
  293. conn := testutil.GetTestSqlConn()
  294. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  295. ts := time.Now().Unix()
  296. err := m.Update(context.Background(), &SysProductMember{
  297. Id: 999999999, ProductCode: "nope", UserId: 1, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  298. })
  299. if err != ErrNotFound {
  300. t.Fatalf("want ErrNotFound got %v", err)
  301. }
  302. }
  303. // TC-0327: 事务内更新
  304. func TestSysProductMemberModel_UpdateWithTx(t *testing.T) {
  305. ctx := context.Background()
  306. conn := testutil.GetTestSqlConn()
  307. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  308. pc := "t_pm_utx_" + testutil.UniqueId()
  309. userId := randProductMemberUserId()
  310. ts := time.Now().Unix()
  311. res, err := m.Insert(ctx, &SysProductMember{
  312. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  313. })
  314. if err != nil {
  315. t.Fatalf("Insert: %v", err)
  316. }
  317. id, _ := res.LastInsertId()
  318. defer testutil.CleanTable(ctx, conn, "sys_product_member", id)
  319. newTs := ts + 100
  320. err = m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  321. return m.UpdateWithTx(c, session, &SysProductMember{
  322. Id: id, ProductCode: pc, UserId: userId, MemberType: "ADMIN", Status: 2, CreateTime: ts, UpdateTime: newTs,
  323. })
  324. })
  325. if err != nil {
  326. t.Fatalf("UpdateWithTx: %v", err)
  327. }
  328. got, err := m.FindOne(ctx, id)
  329. if err != nil {
  330. t.Fatalf("FindOne: %v", err)
  331. }
  332. if got.MemberType != "ADMIN" || got.Status != 2 || got.UpdateTime != newTs {
  333. t.Fatalf("mismatch: %+v", got)
  334. }
  335. }
  336. // TC-0329: 记录不存在
  337. func TestSysProductMemberModel_Delete_NotFound(t *testing.T) {
  338. conn := testutil.GetTestSqlConn()
  339. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  340. err := m.Delete(context.Background(), 999999999)
  341. if err != ErrNotFound {
  342. t.Fatalf("want ErrNotFound got %v", err)
  343. }
  344. }
  345. // TC-0330: 事务内删除
  346. func TestSysProductMemberModel_DeleteWithTx(t *testing.T) {
  347. ctx := context.Background()
  348. conn := testutil.GetTestSqlConn()
  349. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  350. pc := "t_pm_dtx_" + testutil.UniqueId()
  351. userId := randProductMemberUserId()
  352. ts := time.Now().Unix()
  353. res, err := m.Insert(ctx, &SysProductMember{
  354. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  355. })
  356. if err != nil {
  357. t.Fatalf("Insert: %v", err)
  358. }
  359. id, _ := res.LastInsertId()
  360. defer testutil.CleanTable(ctx, conn, "sys_product_member", id)
  361. err = m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  362. return m.DeleteWithTx(c, session, id)
  363. })
  364. if err != nil {
  365. t.Fatalf("DeleteWithTx: %v", err)
  366. }
  367. if _, err := m.FindOne(ctx, id); err != ErrNotFound {
  368. t.Fatalf("after DeleteWithTx want ErrNotFound got %v", err)
  369. }
  370. }
  371. // TC-0331: 正常事务
  372. func TestSysProductMemberModel_TransactCtx_CommitAndRollback(t *testing.T) {
  373. ctx := context.Background()
  374. conn := testutil.GetTestSqlConn()
  375. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  376. pc := "t_pm_txc_" + testutil.UniqueId()
  377. userId := randProductMemberUserId()
  378. ts := time.Now().Unix()
  379. var insertedId int64
  380. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  381. res, err := m.InsertWithTx(c, session, &SysProductMember{
  382. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  383. })
  384. if err != nil {
  385. return err
  386. }
  387. insertedId, _ = res.LastInsertId()
  388. return nil
  389. })
  390. if err != nil {
  391. t.Fatalf("commit: %v", err)
  392. }
  393. defer testutil.CleanTable(ctx, conn, "sys_product_member", insertedId)
  394. got, err := m.FindOne(ctx, insertedId)
  395. if err != nil {
  396. t.Fatalf("FindOne after commit: %v", err)
  397. }
  398. if got.ProductCode != pc {
  399. t.Fatalf("productCode mismatch: %s", got.ProductCode)
  400. }
  401. pc2 := "t_pm_txr_" + testutil.UniqueId()
  402. userId2 := randProductMemberUserId()
  403. err = m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  404. _, err := m.InsertWithTx(c, session, &SysProductMember{
  405. ProductCode: pc2, UserId: userId2, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  406. })
  407. if err != nil {
  408. return err
  409. }
  410. return errors.New("rollback")
  411. })
  412. if err == nil || err.Error() != "rollback" {
  413. t.Fatalf("want rollback error got %v", err)
  414. }
  415. _, err = m.FindOneByProductCodeUserId(ctx, pc2, userId2)
  416. if err != ErrNotFound {
  417. t.Fatalf("after rollback want ErrNotFound got %v", err)
  418. }
  419. }
  420. // TC-0333: 获取表名
  421. func TestSysProductMemberModel_TableName(t *testing.T) {
  422. conn := testutil.GetTestSqlConn()
  423. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  424. if m.TableName() != "`sys_product_member`" {
  425. t.Fatalf("want `sys_product_member` got %s", m.TableName())
  426. }
  427. }
  428. // TC-0335: 单条记录
  429. func TestSysProductMemberModel_BatchInsert_Single(t *testing.T) {
  430. ctx := context.Background()
  431. conn := testutil.GetTestSqlConn()
  432. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  433. pc := "t_pm_bis_" + testutil.UniqueId()
  434. userId := randProductMemberUserId()
  435. ts := time.Now().Unix()
  436. if err := m.BatchInsert(ctx, []*SysProductMember{
  437. {ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts},
  438. }); err != nil {
  439. t.Fatalf("BatchInsert: %v", err)
  440. }
  441. got, err := m.FindOneByProductCodeUserId(ctx, pc, userId)
  442. if err != nil {
  443. t.Fatalf("FindOneByProductCodeUserId: %v", err)
  444. }
  445. defer testutil.CleanTable(ctx, conn, "sys_product_member", got.Id)
  446. if got.MemberType != "MEMBER" {
  447. t.Fatalf("mismatch: %+v", got)
  448. }
  449. }
  450. // TC-0338: 唯一索引冲突
  451. func TestSysProductMemberModel_BatchInsert_UniqueConflict(t *testing.T) {
  452. ctx := context.Background()
  453. conn := testutil.GetTestSqlConn()
  454. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  455. pc := "t_pm_bic_" + testutil.UniqueId()
  456. userId := randProductMemberUserId()
  457. ts := time.Now().Unix()
  458. err := m.BatchInsert(ctx, []*SysProductMember{
  459. {ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts},
  460. {ProductCode: pc, UserId: userId, MemberType: "ADMIN", Status: 1, CreateTime: ts, UpdateTime: ts},
  461. })
  462. if err == nil {
  463. t.Fatal("want error for duplicate")
  464. }
  465. var me *mysql.MySQLError
  466. if !errors.As(err, &me) || me.Number != 1062 {
  467. t.Fatalf("want duplicate key 1062, got %v", err)
  468. }
  469. }
  470. // TC-0343: 空列表
  471. func TestSysProductMemberModel_BatchUpdate_Empty(t *testing.T) {
  472. conn := testutil.GetTestSqlConn()
  473. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  474. if err := m.BatchUpdate(context.Background(), nil); err != nil {
  475. t.Fatalf("nil: %v", err)
  476. }
  477. if err := m.BatchUpdate(context.Background(), []*SysProductMember{}); err != nil {
  478. t.Fatalf("empty: %v", err)
  479. }
  480. }
  481. // TC-0345: 多条记录(3条)
  482. func TestSysProductMemberModel_BatchUpdate_Multi(t *testing.T) {
  483. ctx := context.Background()
  484. conn := testutil.GetTestSqlConn()
  485. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  486. pc := "t_pm_bum_" + testutil.UniqueId()
  487. u1, u2 := randProductMemberUserId(), randProductMemberUserId()
  488. ts := time.Now().Unix()
  489. res1, err := m.Insert(ctx, &SysProductMember{ProductCode: pc, UserId: u1, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts})
  490. if err != nil {
  491. t.Fatalf("Insert1: %v", err)
  492. }
  493. id1, _ := res1.LastInsertId()
  494. res2, err := m.Insert(ctx, &SysProductMember{ProductCode: pc, UserId: u2, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts})
  495. if err != nil {
  496. t.Fatalf("Insert2: %v", err)
  497. }
  498. id2, _ := res2.LastInsertId()
  499. defer testutil.CleanTable(ctx, conn, "sys_product_member", id1, id2)
  500. newTs := ts + 100
  501. err = m.BatchUpdate(ctx, []*SysProductMember{
  502. {Id: id1, ProductCode: pc, UserId: u1, MemberType: "ADMIN", Status: 2, CreateTime: ts, UpdateTime: newTs},
  503. {Id: id2, ProductCode: pc, UserId: u2, MemberType: "ADMIN", Status: 2, CreateTime: ts, UpdateTime: newTs},
  504. })
  505. if err != nil {
  506. t.Fatalf("BatchUpdate: %v", err)
  507. }
  508. got1, err := m.FindOne(ctx, id1)
  509. if err != nil {
  510. t.Fatalf("FindOne1: %v", err)
  511. }
  512. if got1.MemberType != "ADMIN" || got1.Status != 2 || got1.UpdateTime != newTs {
  513. t.Fatalf("got1 mismatch: %+v", got1)
  514. }
  515. got2, err := m.FindOne(ctx, id2)
  516. if err != nil {
  517. t.Fatalf("FindOne2: %v", err)
  518. }
  519. if got2.MemberType != "ADMIN" || got2.Status != 2 || got2.UpdateTime != newTs {
  520. t.Fatalf("got2 mismatch: %+v", got2)
  521. }
  522. }
  523. // TC-0355: 多个id(3个)
  524. func TestSysProductMemberModel_BatchDelete_Multi(t *testing.T) {
  525. ctx := context.Background()
  526. conn := testutil.GetTestSqlConn()
  527. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  528. pc := "t_pm_bdm_" + testutil.UniqueId()
  529. ts := time.Now().Unix()
  530. var ids []int64
  531. for i := 0; i < 3; i++ {
  532. res, err := m.Insert(ctx, &SysProductMember{
  533. ProductCode: pc, UserId: randProductMemberUserId(), MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  534. })
  535. if err != nil {
  536. t.Fatalf("Insert: %v", err)
  537. }
  538. id, _ := res.LastInsertId()
  539. ids = append(ids, id)
  540. }
  541. defer func() {
  542. for _, id := range ids {
  543. testutil.CleanTable(ctx, conn, "sys_product_member", id)
  544. }
  545. }()
  546. if err := m.BatchDelete(ctx, ids); err != nil {
  547. t.Fatalf("BatchDelete: %v", err)
  548. }
  549. for _, id := range ids {
  550. if _, err := m.FindOne(ctx, id); err != ErrNotFound {
  551. t.Fatalf("id %d should be deleted: %v", id, err)
  552. }
  553. }
  554. }
  555. // TC-0354: 单个id
  556. func TestSysProductMemberModel_BatchDelete_Single(t *testing.T) {
  557. ctx := context.Background()
  558. conn := testutil.GetTestSqlConn()
  559. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  560. pc := "t_pm_bds_" + testutil.UniqueId()
  561. userId := randProductMemberUserId()
  562. ts := time.Now().Unix()
  563. res, err := m.Insert(ctx, &SysProductMember{
  564. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  565. })
  566. if err != nil {
  567. t.Fatalf("Insert: %v", err)
  568. }
  569. id, _ := res.LastInsertId()
  570. defer testutil.CleanTable(ctx, conn, "sys_product_member", id)
  571. if err := m.BatchDelete(ctx, []int64{id}); err != nil {
  572. t.Fatalf("BatchDelete: %v", err)
  573. }
  574. if _, err := m.FindOne(ctx, id); err != ErrNotFound {
  575. t.Fatalf("want ErrNotFound got %v", err)
  576. }
  577. }
  578. // TC-0356: 包含不存在id
  579. func TestSysProductMemberModel_BatchDelete_ContainsNonExist(t *testing.T) {
  580. ctx := context.Background()
  581. conn := testutil.GetTestSqlConn()
  582. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  583. pc := "t_pm_bdn_" + testutil.UniqueId()
  584. userId := randProductMemberUserId()
  585. ts := time.Now().Unix()
  586. res, err := m.Insert(ctx, &SysProductMember{
  587. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  588. })
  589. if err != nil {
  590. t.Fatalf("Insert: %v", err)
  591. }
  592. id, _ := res.LastInsertId()
  593. defer testutil.CleanTable(ctx, conn, "sys_product_member", id)
  594. if err := m.BatchDelete(ctx, []int64{id, 999999999}); err != nil {
  595. t.Fatalf("BatchDelete: %v", err)
  596. }
  597. if _, err := m.FindOne(ctx, id); err != ErrNotFound {
  598. t.Fatalf("want ErrNotFound got %v", err)
  599. }
  600. }
  601. // TC-0341: 正常多条
  602. func TestSysProductMemberModel_BatchInsertWithTx_Normal(t *testing.T) {
  603. ctx := context.Background()
  604. conn := testutil.GetTestSqlConn()
  605. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  606. pc := "t_pm_bitn_" + testutil.UniqueId()
  607. u1, u2 := randProductMemberUserId(), randProductMemberUserId()
  608. ts := time.Now().Unix()
  609. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  610. return m.BatchInsertWithTx(c, session, []*SysProductMember{
  611. {ProductCode: pc, UserId: u1, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts},
  612. {ProductCode: pc, UserId: u2, MemberType: "ADMIN", Status: 1, CreateTime: ts, UpdateTime: ts},
  613. })
  614. })
  615. if err != nil {
  616. t.Fatalf("BatchInsertWithTx: %v", err)
  617. }
  618. got1, err := m.FindOneByProductCodeUserId(ctx, pc, u1)
  619. if err != nil {
  620. t.Fatalf("FindOne u1: %v", err)
  621. }
  622. got2, err := m.FindOneByProductCodeUserId(ctx, pc, u2)
  623. if err != nil {
  624. t.Fatalf("FindOne u2: %v", err)
  625. }
  626. defer testutil.CleanTable(ctx, conn, "sys_product_member", got1.Id, got2.Id)
  627. }
  628. // TC-0340: 空列表
  629. func TestSysProductMemberModel_BatchInsertWithTx_Empty(t *testing.T) {
  630. ctx := context.Background()
  631. conn := testutil.GetTestSqlConn()
  632. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  633. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  634. if err := m.BatchInsertWithTx(c, session, nil); err != nil {
  635. return err
  636. }
  637. return m.BatchInsertWithTx(c, session, []*SysProductMember{})
  638. })
  639. if err != nil {
  640. t.Fatalf("BatchInsertWithTx empty: %v", err)
  641. }
  642. }
  643. // TC-0342: 事务回滚
  644. func TestSysProductMemberModel_BatchInsertWithTx_Rollback(t *testing.T) {
  645. ctx := context.Background()
  646. conn := testutil.GetTestSqlConn()
  647. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  648. pc := "t_pm_bitr_" + testutil.UniqueId()
  649. userId := randProductMemberUserId()
  650. ts := time.Now().Unix()
  651. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  652. if err := m.BatchInsertWithTx(c, session, []*SysProductMember{
  653. {ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts},
  654. }); err != nil {
  655. return err
  656. }
  657. return errors.New("rollback")
  658. })
  659. if err == nil || err.Error() != "rollback" {
  660. t.Fatalf("want rollback error got %v", err)
  661. }
  662. _, err = m.FindOneByProductCodeUserId(ctx, pc, userId)
  663. if err != ErrNotFound {
  664. t.Fatalf("after rollback want ErrNotFound got %v", err)
  665. }
  666. }
  667. // TC-0349: 正常多条
  668. func TestSysProductMemberModel_BatchUpdateWithTx_Normal(t *testing.T) {
  669. ctx := context.Background()
  670. conn := testutil.GetTestSqlConn()
  671. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  672. pc := "t_pm_butn_" + testutil.UniqueId()
  673. u1, u2 := randProductMemberUserId(), randProductMemberUserId()
  674. ts := time.Now().Unix()
  675. res1, err := m.Insert(ctx, &SysProductMember{ProductCode: pc, UserId: u1, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts})
  676. if err != nil {
  677. t.Fatalf("Insert1: %v", err)
  678. }
  679. id1, _ := res1.LastInsertId()
  680. res2, err := m.Insert(ctx, &SysProductMember{ProductCode: pc, UserId: u2, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts})
  681. if err != nil {
  682. t.Fatalf("Insert2: %v", err)
  683. }
  684. id2, _ := res2.LastInsertId()
  685. defer testutil.CleanTable(ctx, conn, "sys_product_member", id1, id2)
  686. newTs := ts + 200
  687. err = m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  688. return m.BatchUpdateWithTx(c, session, []*SysProductMember{
  689. {Id: id1, ProductCode: pc, UserId: u1, MemberType: "ADMIN", Status: 2, CreateTime: ts, UpdateTime: newTs},
  690. {Id: id2, ProductCode: pc, UserId: u2, MemberType: "ADMIN", Status: 2, CreateTime: ts, UpdateTime: newTs},
  691. })
  692. })
  693. if err != nil {
  694. t.Fatalf("BatchUpdateWithTx: %v", err)
  695. }
  696. got1, err := m.FindOne(ctx, id1)
  697. if err != nil {
  698. t.Fatalf("FindOne1: %v", err)
  699. }
  700. if got1.MemberType != "ADMIN" || got1.Status != 2 || got1.UpdateTime != newTs {
  701. t.Fatalf("got1 mismatch: %+v", got1)
  702. }
  703. }
  704. // TC-0348: 空列表
  705. func TestSysProductMemberModel_BatchUpdateWithTx_Empty(t *testing.T) {
  706. ctx := context.Background()
  707. conn := testutil.GetTestSqlConn()
  708. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  709. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  710. if err := m.BatchUpdateWithTx(c, session, nil); err != nil {
  711. return err
  712. }
  713. return m.BatchUpdateWithTx(c, session, []*SysProductMember{})
  714. })
  715. if err != nil {
  716. t.Fatalf("BatchUpdateWithTx empty: %v", err)
  717. }
  718. }
  719. // TC-0358: 正常多条
  720. func TestSysProductMemberModel_BatchDeleteWithTx_Normal(t *testing.T) {
  721. ctx := context.Background()
  722. conn := testutil.GetTestSqlConn()
  723. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  724. pc := "t_pm_bdtn_" + testutil.UniqueId()
  725. ts := time.Now().Unix()
  726. var ids []int64
  727. for i := 0; i < 2; i++ {
  728. res, err := m.Insert(ctx, &SysProductMember{
  729. ProductCode: pc, UserId: randProductMemberUserId(), MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  730. })
  731. if err != nil {
  732. t.Fatalf("Insert: %v", err)
  733. }
  734. id, _ := res.LastInsertId()
  735. ids = append(ids, id)
  736. }
  737. defer func() {
  738. for _, id := range ids {
  739. testutil.CleanTable(ctx, conn, "sys_product_member", id)
  740. }
  741. }()
  742. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  743. return m.BatchDeleteWithTx(c, session, ids)
  744. })
  745. if err != nil {
  746. t.Fatalf("BatchDeleteWithTx: %v", err)
  747. }
  748. for _, id := range ids {
  749. if _, err := m.FindOne(ctx, id); err != ErrNotFound {
  750. t.Fatalf("id %d should be deleted: %v", id, err)
  751. }
  752. }
  753. }
  754. // TC-0357: 空ids
  755. func TestSysProductMemberModel_BatchDeleteWithTx_Empty(t *testing.T) {
  756. ctx := context.Background()
  757. conn := testutil.GetTestSqlConn()
  758. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  759. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  760. if err := m.BatchDeleteWithTx(c, session, nil); err != nil {
  761. return err
  762. }
  763. return m.BatchDeleteWithTx(c, session, []int64{})
  764. })
  765. if err != nil {
  766. t.Fatalf("BatchDeleteWithTx empty: %v", err)
  767. }
  768. }
  769. // TC-0323: 事务内可见性
  770. func TestSysProductMemberModel_FindOneWithTx_InsertThenFind(t *testing.T) {
  771. ctx := context.Background()
  772. conn := testutil.GetTestSqlConn()
  773. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  774. pc := "t_pm_fotx_" + testutil.UniqueId()
  775. userId := randProductMemberUserId()
  776. ts := time.Now().Unix()
  777. var insertedId int64
  778. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  779. res, err := m.InsertWithTx(c, session, &SysProductMember{
  780. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: ts, UpdateTime: ts,
  781. })
  782. if err != nil {
  783. return err
  784. }
  785. insertedId, err = res.LastInsertId()
  786. if err != nil {
  787. return err
  788. }
  789. got, err := m.FindOneWithTx(c, session, insertedId)
  790. if err != nil {
  791. return err
  792. }
  793. assert.Equal(t, pc, got.ProductCode)
  794. assert.Equal(t, userId, got.UserId)
  795. assert.Equal(t, "MEMBER", got.MemberType)
  796. return nil
  797. })
  798. require.NoError(t, err)
  799. defer testutil.CleanTable(ctx, conn, "sys_product_member", insertedId)
  800. }
  801. // TC-0322: 事务内记录不存在
  802. func TestSysProductMemberModel_FindOneWithTx_NotFound(t *testing.T) {
  803. ctx := context.Background()
  804. conn := testutil.GetTestSqlConn()
  805. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  806. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  807. _, err := m.FindOneWithTx(c, session, 999999999999)
  808. require.ErrorIs(t, err, ErrNotFound)
  809. return nil
  810. })
  811. require.NoError(t, err)
  812. }
  813. // TC-0393: FindOneByProductCodeUserIdWithTx
  814. func TestSysProductMemberModel_FindOneByProductCodeUserIdWithTx_InsertThenFind(t *testing.T) {
  815. ctx := context.Background()
  816. conn := testutil.GetTestSqlConn()
  817. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  818. pc := "t_pm_fbytx_" + testutil.UniqueId()
  819. userId := randProductMemberUserId()
  820. ts := time.Now().Unix()
  821. var insertedId int64
  822. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  823. res, err := m.InsertWithTx(c, session, &SysProductMember{
  824. ProductCode: pc, UserId: userId, MemberType: "ADMIN", Status: 1, CreateTime: ts, UpdateTime: ts,
  825. })
  826. if err != nil {
  827. return err
  828. }
  829. insertedId, err = res.LastInsertId()
  830. if err != nil {
  831. return err
  832. }
  833. got, err := m.FindOneByProductCodeUserIdWithTx(c, session, pc, userId)
  834. if err != nil {
  835. return err
  836. }
  837. assert.Equal(t, insertedId, got.Id)
  838. assert.Equal(t, pc, got.ProductCode)
  839. assert.Equal(t, userId, got.UserId)
  840. return nil
  841. })
  842. require.NoError(t, err)
  843. defer testutil.CleanTable(ctx, conn, "sys_product_member", insertedId)
  844. }
  845. // TC-0394: FindOneByProductCodeUserIdWithTx
  846. func TestSysProductMemberModel_FindOneByProductCodeUserIdWithTx_NotFound(t *testing.T) {
  847. ctx := context.Background()
  848. conn := testutil.GetTestSqlConn()
  849. m := NewSysProductMemberModel(conn, testutil.GetTestCacheConf(), testutil.GetTestCachePrefix())
  850. err := m.TransactCtx(ctx, func(c context.Context, session sqlx.Session) error {
  851. _, err := m.FindOneByProductCodeUserIdWithTx(c, session, "notexist_"+testutil.UniqueId(), 999999999)
  852. require.ErrorIs(t, err, ErrNotFound)
  853. return nil
  854. })
  855. require.NoError(t, err)
  856. }
  857. // TC-0478 / TC-0480: [REMOVED] 参见 TC-0477;方法已随 L-5 清理一并移除。