hub/internal/user/manager_test.go

873 lines
22 KiB
Go

package user
import (
"context"
"errors"
"fmt"
"testing"
"time"
"github.com/artifacthub/hub/internal/email"
"github.com/artifacthub/hub/internal/hub"
"github.com/artifacthub/hub/internal/tests"
"github.com/jackc/pgx/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"golang.org/x/crypto/bcrypt"
)
func TestCheckAPIKey(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
key []byte
}{
{
"key not provided",
nil,
},
{
"key not provided",
[]byte(""),
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
_, err := m.CheckAPIKey(ctx, tc.key)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("key not found in database", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getAPIKeyUserIDDBQ, []byte("key")).Return(nil, pgx.ErrNoRows)
m := NewManager(db, nil)
output, err := m.CheckAPIKey(ctx, []byte("key"))
assert.NoError(t, err)
assert.False(t, output.Valid)
assert.Empty(t, output.UserID)
db.AssertExpectations(t)
})
t.Run("error getting key from database", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getAPIKeyUserIDDBQ, []byte("key")).Return(nil, tests.ErrFakeDB)
m := NewManager(db, nil)
output, err := m.CheckAPIKey(ctx, []byte("key"))
assert.Equal(t, tests.ErrFakeDB, err)
assert.Nil(t, output)
db.AssertExpectations(t)
})
t.Run("valid key", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getAPIKeyUserIDDBQ, []byte("key")).Return("userID", nil)
m := NewManager(db, nil)
output, err := m.CheckAPIKey(ctx, []byte("key"))
assert.NoError(t, err)
assert.True(t, output.Valid)
assert.Equal(t, "userID", output.UserID)
db.AssertExpectations(t)
})
}
func TestCheckAvailability(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
resourceKind string
value string
}{
{
"invalid resource kind",
"invalid",
"value",
},
{
"invalid value",
"userAlias",
"",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
_, err := m.CheckAvailability(ctx, tc.resourceKind, tc.value)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("database query succeeded", func(t *testing.T) {
testCases := []struct {
resourceKind string
dbQuery string
available bool
}{
{
"userAlias",
checkUserAliasAvailDBQ,
true,
},
}
for _, tc := range testCases {
tc := tc
t.Run(fmt.Sprintf("resource kind: %s", tc.resourceKind), func(t *testing.T) {
t.Parallel()
tc.dbQuery = fmt.Sprintf("select not exists (%s)", tc.dbQuery)
db := &tests.DBMock{}
db.On("QueryRow", ctx, tc.dbQuery, "value").Return(tc.available, nil)
m := NewManager(db, nil)
available, err := m.CheckAvailability(ctx, tc.resourceKind, "value")
assert.NoError(t, err)
assert.Equal(t, tc.available, available)
db.AssertExpectations(t)
})
}
})
t.Run("database error", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
dbQuery := fmt.Sprintf(`select not exists (%s)`, checkUserAliasAvailDBQ)
db.On("QueryRow", ctx, dbQuery, "value").Return(false, tests.ErrFakeDB)
m := NewManager(db, nil)
available, err := m.CheckAvailability(ctx, "userAlias", "value")
assert.Equal(t, tests.ErrFakeDB, err)
assert.False(t, available)
db.AssertExpectations(t)
})
}
func TestCheckCredentials(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
email string
password string
}{
{
"email not provided",
"",
"password",
},
{
"password not provided",
"email",
"",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
_, err := m.CheckCredentials(ctx, tc.email, tc.password)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("credentials provided not found in database", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, checkUserCredsDBQ, "email").Return(nil, pgx.ErrNoRows)
m := NewManager(db, nil)
output, err := m.CheckCredentials(ctx, "email", "pass")
assert.NoError(t, err)
assert.False(t, output.Valid)
assert.Empty(t, output.UserID)
db.AssertExpectations(t)
})
t.Run("error getting credentials from database", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, checkUserCredsDBQ, "email").Return(nil, tests.ErrFakeDB)
m := NewManager(db, nil)
output, err := m.CheckCredentials(ctx, "email", "pass")
assert.Equal(t, tests.ErrFakeDB, err)
assert.Nil(t, output)
db.AssertExpectations(t)
})
t.Run("invalid credentials provided", func(t *testing.T) {
t.Parallel()
pw, _ := bcrypt.GenerateFromPassword([]byte("pass"), bcrypt.DefaultCost)
db := &tests.DBMock{}
db.On("QueryRow", ctx, checkUserCredsDBQ, "email").Return([]interface{}{"userID", string(pw)}, nil)
m := NewManager(db, nil)
output, err := m.CheckCredentials(ctx, "email", "pass2")
assert.NoError(t, err)
assert.False(t, output.Valid)
assert.Empty(t, output.UserID)
db.AssertExpectations(t)
})
t.Run("valid credentials provided", func(t *testing.T) {
t.Parallel()
pw, _ := bcrypt.GenerateFromPassword([]byte("pass"), bcrypt.DefaultCost)
db := &tests.DBMock{}
db.On("QueryRow", ctx, checkUserCredsDBQ, "email").Return([]interface{}{"userID", string(pw)}, nil)
m := NewManager(db, nil)
output, err := m.CheckCredentials(ctx, "email", "pass")
assert.NoError(t, err)
assert.True(t, output.Valid)
assert.Equal(t, "userID", output.UserID)
db.AssertExpectations(t)
})
}
func TestCheckSession(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
sessionID []byte
duration time.Duration
}{
{
"session id not provided",
nil,
10,
},
{
"session id not provided",
[]byte(""),
10,
},
{
"duration not provided",
[]byte("sessionID"),
0,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
_, err := m.CheckSession(ctx, tc.sessionID, tc.duration)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("session not found in database", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getSessionDBQ, []byte("sessionID")).Return(nil, pgx.ErrNoRows)
m := NewManager(db, nil)
output, err := m.CheckSession(ctx, []byte("sessionID"), 1*time.Hour)
assert.NoError(t, err)
assert.False(t, output.Valid)
assert.Empty(t, output.UserID)
db.AssertExpectations(t)
})
t.Run("error getting session from database", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getSessionDBQ, []byte("sessionID")).Return(nil, tests.ErrFakeDB)
m := NewManager(db, nil)
output, err := m.CheckSession(ctx, []byte("sessionID"), 1*time.Hour)
assert.Equal(t, tests.ErrFakeDB, err)
assert.Nil(t, output)
db.AssertExpectations(t)
})
t.Run("session has expired", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getSessionDBQ, []byte("sessionID")).Return([]interface{}{"userID", int64(1)}, nil)
m := NewManager(db, nil)
output, err := m.CheckSession(ctx, []byte("sessionID"), 1*time.Hour)
assert.NoError(t, err)
assert.False(t, output.Valid)
assert.Empty(t, output.UserID)
db.AssertExpectations(t)
})
t.Run("valid session", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getSessionDBQ, []byte("sessionID")).Return([]interface{}{
"userID",
time.Now().Unix(),
}, nil)
m := NewManager(db, nil)
output, err := m.CheckSession(ctx, []byte("sessionID"), 1*time.Hour)
assert.NoError(t, err)
assert.True(t, output.Valid)
assert.Equal(t, "userID", output.UserID)
db.AssertExpectations(t)
})
}
func TestDeleteSession(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
sessionID []byte
duration time.Duration
}{
{
"session id not provided",
nil,
10,
},
{
"session id not provided",
[]byte(""),
10,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
err := m.DeleteSession(ctx, tc.sessionID)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("valid input", func(t *testing.T) {
testCases := []struct {
description string
dbResponse interface{}
}{
{
"session deleted successfully",
nil,
},
{
"error deleting session from database",
tests.ErrFakeDB,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("Exec", ctx, deleteSessionDBQ, []byte("sessionID")).Return(tc.dbResponse)
m := NewManager(db, nil)
err := m.DeleteSession(ctx, []byte("sessionID"))
assert.Equal(t, tc.dbResponse, err)
db.AssertExpectations(t)
})
}
})
}
func TestGetProfile(t *testing.T) {
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
t.Run("user id not found in ctx", func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
assert.Panics(t, func() {
_, _ = m.GetProfile(context.Background())
})
})
t.Run("database error", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserProfileDBQ, "userID").Return(nil, tests.ErrFakeDB)
m := NewManager(db, nil)
profile, err := m.GetProfile(ctx)
assert.Equal(t, tests.ErrFakeDB, err)
assert.Nil(t, profile)
db.AssertExpectations(t)
})
t.Run("database query succeeded", func(t *testing.T) {
t.Parallel()
expectedProfile := &hub.User{
Alias: "alias",
FirstName: "first_name",
LastName: "last_name",
Email: "email",
ProfileImageID: "profile_image_id",
}
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserProfileDBQ, "userID").Return([]byte(`
{
"alias": "alias",
"first_name": "first_name",
"last_name": "last_name",
"email": "email",
"profile_image_id": "profile_image_id"
}
`), nil)
m := NewManager(db, nil)
profile, err := m.GetProfile(ctx)
assert.NoError(t, err)
assert.Equal(t, expectedProfile, profile)
db.AssertExpectations(t)
})
}
func TestGetProfileJSON(t *testing.T) {
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
t.Run("user id not found in ctx", func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
assert.Panics(t, func() {
_, _ = m.GetProfileJSON(context.Background())
})
})
t.Run("database query succeeded", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserProfileDBQ, "userID").Return([]byte("dataJSON"), nil)
m := NewManager(db, nil)
data, err := m.GetProfileJSON(ctx)
assert.NoError(t, err)
assert.Equal(t, []byte("dataJSON"), data)
db.AssertExpectations(t)
})
t.Run("database error", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserProfileDBQ, "userID").Return(nil, tests.ErrFakeDB)
m := NewManager(db, nil)
data, err := m.GetProfileJSON(ctx)
assert.Equal(t, tests.ErrFakeDB, err)
assert.Nil(t, data)
db.AssertExpectations(t)
})
}
func TestGetUserID(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
_, err := m.GetUserID(ctx, "")
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
})
t.Run("database query succeeded", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserIDDBQ, "email").Return("userID", nil)
m := NewManager(db, nil)
userID, err := m.GetUserID(ctx, "email")
assert.NoError(t, err)
assert.Equal(t, "userID", userID)
db.AssertExpectations(t)
})
t.Run("database error", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserIDDBQ, "email").Return("", tests.ErrFakeDB)
m := NewManager(db, nil)
userID, err := m.GetUserID(ctx, "email")
assert.Equal(t, tests.ErrFakeDB, err)
assert.Empty(t, userID)
db.AssertExpectations(t)
})
}
func TestRegisterSession(t *testing.T) {
ctx := context.Background()
s := &hub.Session{
UserID: "00000000-0000-0000-0000-000000000001",
IP: "192.168.1.100",
UserAgent: "Safari 13.0.5",
}
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
userID string
}{
{
"user id not provided",
"",
},
{
"invalid user id",
"invalid",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
s := &hub.Session{UserID: tc.userID}
_, err := m.RegisterSession(ctx, s)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("successful session registration", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, registerSessionDBQ, mock.Anything).Return([]byte("sessionID"), nil)
m := NewManager(db, nil)
sessionID, err := m.RegisterSession(ctx, s)
assert.NoError(t, err)
assert.Equal(t, []byte("sessionID"), sessionID)
db.AssertExpectations(t)
})
t.Run("database error", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, registerSessionDBQ, mock.Anything).Return(nil, tests.ErrFakeDB)
m := NewManager(db, nil)
sessionID, err := m.RegisterSession(ctx, s)
assert.Equal(t, tests.ErrFakeDB, err)
assert.Nil(t, sessionID)
db.AssertExpectations(t)
})
}
func TestRegisterUser(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
user *hub.User
baseURL string
}{
{
"alias not provided",
&hub.User{},
"http://baseurl.com",
},
{
"email not provided",
&hub.User{Alias: "user1"},
"http://baseurl.com",
},
{
"invalid base url",
&hub.User{Alias: "user1", Email: "email"},
"invalid",
},
{
"invalid profile image id",
&hub.User{Alias: "user1", Email: "email", ProfileImageID: "invalid"},
"http://baseurl.com",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
es := &email.SenderMock{}
es.On("SendEmail", mock.Anything).Return(nil)
m := NewManager(nil, es)
err := m.RegisterUser(ctx, tc.user, tc.baseURL)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("successful user registration in database", func(t *testing.T) {
code := "emailVerificationCode"
testCases := []struct {
description string
emailSenderResponse error
}{
{
"email verification code sent successfully",
nil,
},
{
"error sending email verification code",
email.ErrFakeSenderFailure,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, registerUserDBQ, mock.Anything).Return(&code, nil)
es := &email.SenderMock{}
es.On("SendEmail", mock.Anything).Return(tc.emailSenderResponse)
m := NewManager(db, es)
u := &hub.User{
Alias: "alias",
FirstName: "first_name",
LastName: "last_name",
Email: "email@email.com",
Password: "password",
ProfileImageID: "00000000-0000-0000-0000-000000000001",
}
err := m.RegisterUser(ctx, u, "http://baseurl.com")
assert.Equal(t, tc.emailSenderResponse, err)
assert.NoError(t, bcrypt.CompareHashAndPassword([]byte(u.Password), []byte("password")))
db.AssertExpectations(t)
es.AssertExpectations(t)
})
}
})
t.Run("database error registering user", func(t *testing.T) {
t.Parallel()
code := ""
db := &tests.DBMock{}
db.On("QueryRow", ctx, registerUserDBQ, mock.Anything).Return(&code, tests.ErrFakeDB)
m := NewManager(db, nil)
u := &hub.User{
Alias: "alias",
Email: "email@email.com",
}
err := m.RegisterUser(ctx, u, "http://baseurl.com")
assert.Equal(t, tests.ErrFakeDB, err)
db.AssertExpectations(t)
})
}
func TestUpdatePassword(t *testing.T) {
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
oldHashed, _ := bcrypt.GenerateFromPassword([]byte("old"), bcrypt.DefaultCost)
t.Run("user id not found in ctx", func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
assert.Panics(t, func() {
_ = m.UpdatePassword(context.Background(), "old", "new")
})
})
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
old string
new string
}{
{
"old password not provided",
"",
"new",
},
{
"new password not provided",
"old",
"",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
err := m.UpdatePassword(ctx, tc.old, tc.new)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("database error getting user password", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserPasswordDBQ, "userID").Return("", tests.ErrFakeDB)
m := NewManager(db, nil)
err := m.UpdatePassword(ctx, "old", "new")
assert.Equal(t, tests.ErrFakeDB, err)
db.AssertExpectations(t)
})
t.Run("invalid user password provided", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserPasswordDBQ, "userID").Return(string(oldHashed), nil)
m := NewManager(db, nil)
err := m.UpdatePassword(ctx, "old2", "new")
assert.Error(t, err)
db.AssertExpectations(t)
})
t.Run("database error updating password", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserPasswordDBQ, "userID").Return(string(oldHashed), nil)
db.On("Exec", ctx, updateUserPasswordDBQ, "userID", mock.Anything, mock.Anything).
Return(tests.ErrFakeDB)
m := NewManager(db, nil)
err := m.UpdatePassword(ctx, "old", "new")
assert.Equal(t, tests.ErrFakeDB, err)
db.AssertExpectations(t)
})
t.Run("successful password update", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, getUserPasswordDBQ, "userID").Return(string(oldHashed), nil)
db.On("Exec", ctx, updateUserPasswordDBQ, "userID", mock.Anything, mock.Anything).Return(nil)
m := NewManager(db, nil)
err := m.UpdatePassword(ctx, "old", "new")
assert.NoError(t, err)
db.AssertExpectations(t)
})
}
func TestUpdateProfile(t *testing.T) {
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
t.Run("user id not found in ctx", func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
assert.Panics(t, func() {
_ = m.UpdateProfile(context.Background(), &hub.User{})
})
})
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
errMsg string
user *hub.User
}{
{
"alias not provided",
&hub.User{},
},
{
"invalid profile image id",
&hub.User{Alias: "user1", Email: "email", ProfileImageID: "invalid"},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.errMsg, func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
err := m.UpdateProfile(ctx, tc.user)
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
assert.Contains(t, err.Error(), tc.errMsg)
})
}
})
t.Run("database query succeeded", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("Exec", ctx, updateUserProfileDBQ, "userID", mock.Anything).Return(nil)
m := NewManager(db, nil)
err := m.UpdateProfile(ctx, &hub.User{Alias: "user1"})
assert.NoError(t, err)
db.AssertExpectations(t)
})
t.Run("database error", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("Exec", ctx, updateUserProfileDBQ, "userID", mock.Anything).Return(tests.ErrFakeDB)
m := NewManager(db, nil)
err := m.UpdateProfile(ctx, &hub.User{Alias: "user1"})
assert.Equal(t, tests.ErrFakeDB, err)
db.AssertExpectations(t)
})
}
func TestVerifyEmail(t *testing.T) {
ctx := context.Background()
t.Run("invalid input", func(t *testing.T) {
t.Parallel()
m := NewManager(nil, nil)
_, err := m.VerifyEmail(ctx, "")
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
})
t.Run("successful email verification", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, verifyEmailDBQ, "emailVerificationCode").Return(true, nil)
m := NewManager(db, nil)
verified, err := m.VerifyEmail(ctx, "emailVerificationCode")
assert.NoError(t, err)
assert.True(t, verified)
db.AssertExpectations(t)
})
t.Run("database error verifying email", func(t *testing.T) {
t.Parallel()
db := &tests.DBMock{}
db.On("QueryRow", ctx, verifyEmailDBQ, "emailVerificationCode").Return(false, tests.ErrFakeDB)
m := NewManager(db, nil)
verified, err := m.VerifyEmail(ctx, "emailVerificationCode")
assert.Equal(t, tests.ErrFakeDB, err)
assert.False(t, verified)
db.AssertExpectations(t)
})
}