user_name_repo_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // 用户显示名批量只读仓储单测(D4:academic 端点 53 的 `realName` 数据源)。
  2. //
  3. // 为什么自带 sqlite 库而不走 `setup(t)`:本包的 `setup` 依赖 `UNIFIED_TEST_DSN`(MySQL 集成测试),
  4. // 未设置时整包 Skip;本用例要证明的是**三条纯逻辑口径**(NULL → 不返回、空白 → 不返回、批量去重),
  5. // 与方言无关,用 sqlite 才能在默认 CI 环境真跑起来。
  6. package repository
  7. import (
  8. "context"
  9. "path/filepath"
  10. "testing"
  11. "time"
  12. gormsqlite "github.com/glebarez/sqlite"
  13. "gorm.io/gorm"
  14. "yuansiwei/unified-backend/internal/identity/model"
  15. )
  16. // newUserNameTestDB 建只含 `t_user` 的 sqlite 库。
  17. func newUserNameTestDB(t *testing.T) *gorm.DB {
  18. t.Helper()
  19. dsn := filepath.Join(t.TempDir(), "user_name_repo_test.db")
  20. db, err := gorm.Open(gormsqlite.Open(dsn), &gorm.Config{})
  21. if err != nil {
  22. t.Fatalf("gorm.Open(显示名测试库) 失败: %v", err)
  23. }
  24. sqlDB, err := db.DB()
  25. if err != nil {
  26. t.Fatalf("取 sql.DB 失败: %v", err)
  27. }
  28. sqlDB.SetMaxOpenConns(1)
  29. t.Cleanup(func() { _ = sqlDB.Close() })
  30. if err := db.AutoMigrate(&model.User{}); err != nil {
  31. t.Fatalf("AutoMigrate(t_user) 失败: %v", err)
  32. }
  33. return db
  34. }
  35. // insertUser 落一个用户(display_name 可 NULL)。
  36. func insertUser(t *testing.T, db *gorm.DB, uid string, displayName *string) {
  37. t.Helper()
  38. row := &model.User{CanonicalUserID: uid, DisplayName: displayName}
  39. if err := db.Create(row).Error; err != nil {
  40. t.Fatalf("插入用户 %s 失败: %v", uid, err)
  41. }
  42. _ = time.Now()
  43. }
  44. // TestDisplayNamesContracts 三条口径 + 批量去重(**任一条写错都会让端点 53 的姓名列出现脏值**)。
  45. //
  46. // A 有名字 → 返回 "张三"
  47. // B display_name 为 NULL → **不进 map**(调用方下发 null)
  48. // C display_name 为空白串 → **不进 map**(不能把 " " 当姓名)
  49. // D 有名字但重复传两次 → 只查一次、结果一次
  50. // E 库里不存在 → 不进 map
  51. func TestDisplayNamesContracts(t *testing.T) {
  52. db := newUserNameTestDB(t)
  53. const (
  54. userA = "01HUSERA0000000000000000A"
  55. userB = "01HUSERB0000000000000000B"
  56. userC = "01HUSERC0000000000000000C"
  57. userD = "01HUSERD0000000000000000D"
  58. userE = "01HUSERE0000000000000000E"
  59. )
  60. insertUser(t, db, userA, strPtr("张三"))
  61. insertUser(t, db, userB, nil)
  62. insertUser(t, db, userC, strPtr(" "))
  63. insertUser(t, db, userD, strPtr("李四"))
  64. repo := NewUserNameRepo(db)
  65. names, err := repo.DisplayNames(context.Background(),
  66. []string{userA, userB, userC, userD, userD, userE, " "})
  67. if err != nil {
  68. t.Fatalf("DisplayNames 失败: %v", err)
  69. }
  70. if got, ok := names[userA]; !ok || got != "张三" {
  71. t.Fatalf("A = %q(在 map 内=%v),期望 张三", got, ok)
  72. }
  73. if _, ok := names[userB]; ok {
  74. t.Fatalf("B 在 map 内:display_name 为 NULL 时**不得**返回(调用方要据此下发 null)")
  75. }
  76. if _, ok := names[userC]; ok {
  77. t.Fatalf("C 在 map 内:display_name 为空白串时**不得**返回(空白不是姓名)")
  78. }
  79. if got, ok := names[userD]; !ok || got != "李四" {
  80. t.Fatalf("D = %q(在 map 内=%v),期望 李四", got, ok)
  81. }
  82. if _, ok := names[userE]; ok {
  83. t.Fatalf("E 在 map 内:库中不存在该用户,不得返回")
  84. }
  85. if len(names) != 2 {
  86. t.Fatalf("返回条数 = %d,期望 2(只有 A/D 有真名字):%v", len(names), names)
  87. }
  88. }
  89. // TestDisplayNamesEmptyInput 空入参不发 SQL、返回空 map(不是 nil,避免调用方 nil 解引用)。
  90. func TestDisplayNamesEmptyInput(t *testing.T) {
  91. db := newUserNameTestDB(t)
  92. repo := NewUserNameRepo(db)
  93. for _, ids := range [][]string{nil, {}, {"", " "}} {
  94. names, err := repo.DisplayNames(context.Background(), ids)
  95. if err != nil {
  96. t.Fatalf("空入参不该报错: %v", err)
  97. }
  98. if names == nil {
  99. t.Fatalf("空入参应返回空 map 而非 nil(入参 %v)", ids)
  100. }
  101. if len(names) != 0 {
  102. t.Fatalf("空入参应返回 0 条,实际 %d", len(names))
  103. }
  104. }
  105. }
  106. // TestDisplayNamesNilDB 未装配 DB 时返回错误(不得 panic)。
  107. func TestDisplayNamesNilDB(t *testing.T) {
  108. repo := NewUserNameRepo(nil)
  109. if _, err := repo.DisplayNames(context.Background(), []string{"01HUSERA0000000000000000A"}); err == nil {
  110. t.Fatal("DB 为 nil 时应返回错误,而不是静默返回空 map(那会让\"没名字\"与\"库连不上\"混为一谈)")
  111. }
  112. }