users_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright 2020 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package db
  5. import (
  6. "context"
  7. "testing"
  8. "time"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. "gogs.io/gogs/internal/auth"
  12. "gogs.io/gogs/internal/errutil"
  13. )
  14. func TestUsers(t *testing.T) {
  15. if testing.Short() {
  16. t.Skip()
  17. }
  18. t.Parallel()
  19. tables := []interface{}{new(User), new(EmailAddress)}
  20. db := &users{
  21. DB: initTestDB(t, "users", tables...),
  22. }
  23. for _, tc := range []struct {
  24. name string
  25. test func(*testing.T, *users)
  26. }{
  27. {"Authenticate", usersAuthenticate},
  28. {"Create", usersCreate},
  29. {"GetByEmail", usersGetByEmail},
  30. {"GetByID", usersGetByID},
  31. {"GetByUsername", usersGetByUsername},
  32. } {
  33. t.Run(tc.name, func(t *testing.T) {
  34. t.Cleanup(func() {
  35. err := clearTables(t, db.DB, tables...)
  36. require.NoError(t, err)
  37. })
  38. tc.test(t, db)
  39. })
  40. if t.Failed() {
  41. break
  42. }
  43. }
  44. }
  45. // TODO: Only local account is tested, tests for external account will be added
  46. // along with addressing https://github.com/gogs/gogs/issues/6115.
  47. func usersAuthenticate(t *testing.T, db *users) {
  48. ctx := context.Background()
  49. password := "pa$$word"
  50. alice, err := db.Create(ctx, "alice", "[email protected]",
  51. CreateUserOpts{
  52. Password: password,
  53. },
  54. )
  55. require.NoError(t, err)
  56. t.Run("user not found", func(t *testing.T) {
  57. _, err := db.Authenticate(ctx, "bob", password, -1)
  58. wantErr := auth.ErrBadCredentials{Args: map[string]interface{}{"login": "bob"}}
  59. assert.Equal(t, wantErr, err)
  60. })
  61. t.Run("invalid password", func(t *testing.T) {
  62. _, err := db.Authenticate(ctx, alice.Name, "bad_password", -1)
  63. wantErr := auth.ErrBadCredentials{Args: map[string]interface{}{"login": alice.Name, "userID": alice.ID}}
  64. assert.Equal(t, wantErr, err)
  65. })
  66. t.Run("via email and password", func(t *testing.T) {
  67. user, err := db.Authenticate(ctx, alice.Email, password, -1)
  68. require.NoError(t, err)
  69. assert.Equal(t, alice.Name, user.Name)
  70. })
  71. t.Run("via username and password", func(t *testing.T) {
  72. user, err := db.Authenticate(ctx, alice.Name, password, -1)
  73. require.NoError(t, err)
  74. assert.Equal(t, alice.Name, user.Name)
  75. })
  76. }
  77. func usersCreate(t *testing.T, db *users) {
  78. ctx := context.Background()
  79. alice, err := db.Create(ctx, "alice", "[email protected]",
  80. CreateUserOpts{
  81. Activated: true,
  82. },
  83. )
  84. require.NoError(t, err)
  85. t.Run("name not allowed", func(t *testing.T) {
  86. _, err := db.Create(ctx, "-", "", CreateUserOpts{})
  87. wantErr := ErrNameNotAllowed{args: errutil.Args{"reason": "reserved", "name": "-"}}
  88. assert.Equal(t, wantErr, err)
  89. })
  90. t.Run("name already exists", func(t *testing.T) {
  91. _, err := db.Create(ctx, alice.Name, "", CreateUserOpts{})
  92. wantErr := ErrUserAlreadyExist{args: errutil.Args{"name": alice.Name}}
  93. assert.Equal(t, wantErr, err)
  94. })
  95. t.Run("email already exists", func(t *testing.T) {
  96. _, err := db.Create(ctx, "bob", alice.Email, CreateUserOpts{})
  97. wantErr := ErrEmailAlreadyUsed{args: errutil.Args{"email": alice.Email}}
  98. assert.Equal(t, wantErr, err)
  99. })
  100. user, err := db.GetByUsername(ctx, alice.Name)
  101. require.NoError(t, err)
  102. assert.Equal(t, db.NowFunc().Format(time.RFC3339), user.Created.UTC().Format(time.RFC3339))
  103. assert.Equal(t, db.NowFunc().Format(time.RFC3339), user.Updated.UTC().Format(time.RFC3339))
  104. }
  105. func usersGetByEmail(t *testing.T, db *users) {
  106. ctx := context.Background()
  107. t.Run("empty email", func(t *testing.T) {
  108. _, err := db.GetByEmail(ctx, "")
  109. wantErr := ErrUserNotExist{args: errutil.Args{"email": ""}}
  110. assert.Equal(t, wantErr, err)
  111. })
  112. t.Run("ignore organization", func(t *testing.T) {
  113. // TODO: Use Orgs.Create to replace SQL hack when the method is available.
  114. org, err := db.Create(ctx, "gogs", "[email protected]", CreateUserOpts{})
  115. require.NoError(t, err)
  116. err = db.Model(&User{}).Where("id", org.ID).UpdateColumn("type", UserOrganization).Error
  117. require.NoError(t, err)
  118. _, err = db.GetByEmail(ctx, org.Email)
  119. wantErr := ErrUserNotExist{args: errutil.Args{"email": org.Email}}
  120. assert.Equal(t, wantErr, err)
  121. })
  122. t.Run("by primary email", func(t *testing.T) {
  123. alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOpts{})
  124. require.NoError(t, err)
  125. _, err = db.GetByEmail(ctx, alice.Email)
  126. wantErr := ErrUserNotExist{args: errutil.Args{"email": alice.Email}}
  127. assert.Equal(t, wantErr, err)
  128. // Mark user as activated
  129. // TODO: Use UserEmails.Verify to replace SQL hack when the method is available.
  130. err = db.Model(&User{}).Where("id", alice.ID).UpdateColumn("is_active", true).Error
  131. require.NoError(t, err)
  132. user, err := db.GetByEmail(ctx, alice.Email)
  133. require.NoError(t, err)
  134. assert.Equal(t, alice.Name, user.Name)
  135. })
  136. t.Run("by secondary email", func(t *testing.T) {
  137. bob, err := db.Create(ctx, "bob", "[email protected]", CreateUserOpts{})
  138. require.NoError(t, err)
  139. // TODO: Use UserEmails.Create to replace SQL hack when the method is available.
  140. email2 := "[email protected]"
  141. err = db.Exec(`INSERT INTO email_address (uid, email) VALUES (?, ?)`, bob.ID, email2).Error
  142. require.NoError(t, err)
  143. _, err = db.GetByEmail(ctx, email2)
  144. wantErr := ErrUserNotExist{args: errutil.Args{"email": email2}}
  145. assert.Equal(t, wantErr, err)
  146. // TODO: Use UserEmails.Verify to replace SQL hack when the method is available.
  147. err = db.Exec(`UPDATE email_address SET is_activated = ? WHERE email = ?`, true, email2).Error
  148. require.NoError(t, err)
  149. user, err := db.GetByEmail(ctx, email2)
  150. require.NoError(t, err)
  151. assert.Equal(t, bob.Name, user.Name)
  152. })
  153. }
  154. func usersGetByID(t *testing.T, db *users) {
  155. ctx := context.Background()
  156. alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOpts{})
  157. require.NoError(t, err)
  158. user, err := db.GetByID(ctx, alice.ID)
  159. require.NoError(t, err)
  160. assert.Equal(t, alice.Name, user.Name)
  161. _, err = db.GetByID(ctx, 404)
  162. wantErr := ErrUserNotExist{args: errutil.Args{"userID": int64(404)}}
  163. assert.Equal(t, wantErr, err)
  164. }
  165. func usersGetByUsername(t *testing.T, db *users) {
  166. ctx := context.Background()
  167. alice, err := db.Create(ctx, "alice", "[email protected]", CreateUserOpts{})
  168. require.NoError(t, err)
  169. user, err := db.GetByUsername(ctx, alice.Name)
  170. require.NoError(t, err)
  171. assert.Equal(t, alice.Name, user.Name)
  172. _, err = db.GetByUsername(ctx, "bad_username")
  173. wantErr := ErrUserNotExist{args: errutil.Args{"name": "bad_username"}}
  174. assert.Equal(t, wantErr, err)
  175. }