chat_back_go/internal/repository/users_test.go

695 lines
21 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"database/sql"
"errors"
"fmt"
"github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"testing"
"time"
"git.urec56.ru/urec/chat_back_go/internal/database"
"git.urec56.ru/urec/chat_back_go/internal/domain"
mock_logger "git.urec56.ru/urec/chat_back_go/internal/logger/mocks"
)
func Test_newUser(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
db, _, dbClose := database.GetMockDBx(t)
defer dbClose()
log := mock_logger.NewMockLog(c)
repo := newUser(db, log)
assert.Equal(t, &userRepository{db: db, l: log}, repo)
}
func TestUserRepository_GetByID(t *testing.T) {
type mockBehavior func(mock sqlmock.Sqlmock, userID int, rows *sqlmock.Rows, err error)
testTable := []struct {
name string
userID int
mockBehavior mockBehavior
dbRows *sqlmock.Rows
dbErr error
ud domain.User
expectedUser domain.User
expectedErr error
}{
{
name: "ok",
userID: 1,
mockBehavior: func(mock sqlmock.Sqlmock, userID int, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users WHERE id = \$1`).WithArgs(userID).WillReturnRows(rows)
},
dbRows: sqlmock.NewRows(
[]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
},
),
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedUser: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
},
{
name: "user_not_found",
mockBehavior: func(mock sqlmock.Sqlmock, userID int, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users WHERE id = \$1`).WithArgs(userID).WillReturnError(err)
},
dbRows: sqlmock.NewRows(
[]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
},
),
dbErr: sql.ErrNoRows,
expectedErr: domain.UserNotFoundError,
},
{
name: "internal_error",
mockBehavior: func(mock sqlmock.Sqlmock, userID int, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users WHERE id = \$1`).WithArgs(userID).WillReturnError(err)
},
dbRows: sqlmock.NewRows(
[]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
},
),
dbErr: errors.New("some error"),
expectedErr: domain.InternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
db, mock, dbClose := database.GetMockDBx(t)
defer dbClose()
tc.mockBehavior(mock, tc.userID, tc.dbRows.AddRow(
tc.ud.ID,
tc.ud.Role,
tc.ud.Username,
tc.ud.Email,
tc.ud.HashedPassword,
tc.ud.AvatarImage,
tc.ud.BlackPhoenix,
tc.ud.DateOfBirth,
tc.ud.DateOfRegistration,
), tc.dbErr)
repo := &userRepository{db: db}
u, err := repo.GetByID(tc.userID)
assert.Equal(t, tc.expectedUser, u)
assert.ErrorIs(t, err, tc.expectedErr)
assert.NoError(t, mock.ExpectationsWereMet())
})
}
}
func TestUserRepository_GetAll(t *testing.T) {
type mockBehavior func(mock sqlmock.Sqlmock, username string, rows *sqlmock.Rows, err error)
type logBehavior func(l *mock_logger.MockLog, err error)
testTable := []struct {
name string
username string
mockBehavior mockBehavior
logBehavior logBehavior
dbRows *sqlmock.Rows
dbErr error
ud domain.User
expectedUsers []domain.User
expectedErr error
}{
{
name: "ok",
mockBehavior: func(mock sqlmock.Sqlmock, username string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(fmt.Sprintf(`SELECT \* FROM users WHERE username ILIKE \$1 AND role != %d`, domain.AdminUser)).WithArgs(username).WillReturnRows(rows)
},
logBehavior: func(l *mock_logger.MockLog, err error) {},
dbRows: sqlmock.NewRows(
[]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
},
),
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedUsers: []domain.User{
{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
},
},
{
name: "any_error",
mockBehavior: func(mock sqlmock.Sqlmock, username string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(fmt.Sprintf(`SELECT \* FROM users WHERE username ILIKE \$1 AND role != %d`, domain.AdminUser)).WithArgs(username).WillReturnError(err)
},
logBehavior: func(l *mock_logger.MockLog, err error) {
l.EXPECT().Errorf("getting users: %s", err.Error())
},
dbRows: sqlmock.NewRows(
[]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
},
),
dbErr: errors.New("some error"),
expectedErr: domain.InternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
db, mock, dbClose := database.GetMockDBx(t)
defer dbClose()
log := mock_logger.NewMockLog(c)
username := fmt.Sprint("%", tc.username, "%")
tc.mockBehavior(mock, username, tc.dbRows.AddRow(
tc.ud.ID,
tc.ud.Role,
tc.ud.Username,
tc.ud.Email,
tc.ud.HashedPassword,
tc.ud.AvatarImage,
tc.ud.BlackPhoenix,
tc.ud.DateOfBirth,
tc.ud.DateOfRegistration,
), tc.dbErr)
tc.logBehavior(log, tc.dbErr)
repo := &userRepository{db: db, l: log}
users, err := repo.GetAll(tc.username)
assert.Equal(t, tc.expectedUsers, users)
assert.ErrorIs(t, err, tc.expectedErr)
assert.NoError(t, mock.ExpectationsWereMet())
})
}
}
func TestUserRepository_FindOne(t *testing.T) {
type mockBehavior func(mock sqlmock.Sqlmock, username, email string, rows *sqlmock.Rows, err error)
dbRows := sqlmock.NewRows([]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
})
okUd := domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
}
okExpectedUser := domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
}
testTable := []struct {
name string
username string
email string
mockBehavior mockBehavior
dbRows *sqlmock.Rows
dbErr error
ud domain.User
expectedUser domain.User
expectedErr error
}{
{
name: "ok_1",
username: "urec",
email: "mail@mail.ru",
mockBehavior: func(mock sqlmock.Sqlmock, username, email string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users WHERE username = \$1 AND email = \$2 LIMIT 1`).WithArgs(username, email).WillReturnRows(rows)
},
dbRows: dbRows,
ud: okUd,
expectedUser: okExpectedUser,
},
{
name: "ok_2",
username: "urec",
mockBehavior: func(mock sqlmock.Sqlmock, username, email string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users WHERE username = \$1 LIMIT 1`).WithArgs(username).WillReturnRows(rows)
},
dbRows: dbRows,
ud: okUd,
expectedUser: okExpectedUser,
},
{
name: "ok_3",
email: "mail@mail.ru",
mockBehavior: func(mock sqlmock.Sqlmock, username, email string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users WHERE email = \$1 LIMIT 1`).WithArgs(email).WillReturnRows(rows)
},
dbRows: dbRows,
ud: okUd,
expectedUser: okExpectedUser,
},
{
name: "ok_4",
mockBehavior: func(mock sqlmock.Sqlmock, username, email string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users LIMIT 1`).WillReturnRows(rows)
},
dbRows: dbRows,
ud: okUd,
expectedUser: okExpectedUser,
},
{
name: "any_error",
mockBehavior: func(mock sqlmock.Sqlmock, username, email string, rows *sqlmock.Rows, err error) {
mock.ExpectQuery(`SELECT \* FROM users LIMIT 1`).WillReturnError(err)
},
dbRows: dbRows,
dbErr: errors.New("some error"),
expectedErr: domain.InternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
db, mock, dbClose := database.GetMockDBx(t)
defer dbClose()
tc.mockBehavior(mock, tc.username, tc.email, tc.dbRows.AddRow(
tc.ud.ID,
tc.ud.Role,
tc.ud.Username,
tc.ud.Email,
tc.ud.HashedPassword,
tc.ud.AvatarImage,
tc.ud.BlackPhoenix,
tc.ud.DateOfBirth,
tc.ud.DateOfRegistration,
), tc.dbErr)
repo := &userRepository{db: db}
u, err := repo.FindOne(tc.username, tc.email)
assert.Equal(t, tc.expectedUser, u)
assert.ErrorIs(t, err, tc.expectedErr)
assert.NoError(t, mock.ExpectationsWereMet())
})
}
}
func TestUserRepository_Register(t *testing.T) {
type mockParams struct {
mock sqlmock.Sqlmock
email, hashedPassword, username, avatarImage string
dateOfBirth time.Time
userID int
rows *sqlmock.Rows
err error
}
type mockBehavior func(p mockParams)
type logBehavior func(log *mock_logger.MockLog, err error)
dbRows := sqlmock.NewRows([]string{
"id",
"role",
"username",
"email",
"hashed_password",
"avatar_image",
"black_phoenix",
"date_of_birth",
"date_of_registration",
})
testTable := []struct {
name string
mockParams mockParams
mockBehavior mockBehavior
logBehavior logBehavior
ud domain.User
expectedUser domain.User
expectedErr error
}{
{
name: "ok",
mockParams: mockParams{
rows: dbRows,
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin()
p.mock.ExpectQuery(
`INSERT INTO users \(email, hashed_password, username, date_of_birth\) VALUES \(\$1, \$2, \$3, \$4\) RETURNING \*`,
).WithArgs(p.email, p.hashedPassword, p.username, p.dateOfBirth).WillReturnRows(p.rows)
p.mock.ExpectExec(
`INSERT INTO user_avatar \(user_id, avatar_image\) VALUES \(\$1, \$2\)`,
).WithArgs(p.userID, p.avatarImage).WillReturnResult(sqlmock.NewResult(1, 1))
p.mock.ExpectCommit()
},
logBehavior: func(log *mock_logger.MockLog, err error) {},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedUser: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
},
{
name: "user_already_exists",
mockParams: mockParams{
rows: dbRows,
err: database.IntegrityError,
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin()
p.mock.ExpectQuery(
`INSERT INTO users \(email, hashed_password, username, date_of_birth\) VALUES \(\$1, \$2, \$3, \$4\) RETURNING \*`,
).WithArgs(p.email, p.hashedPassword, p.username, p.dateOfBirth).WillReturnError(p.err)
p.mock.ExpectRollback()
},
logBehavior: func(log *mock_logger.MockLog, err error) {},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedErr: domain.UserAlreadyExistsError,
},
{
name: "begin_error",
mockParams: mockParams{
rows: dbRows,
err: errors.New("some error"),
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin().WillReturnError(p.err)
},
logBehavior: func(log *mock_logger.MockLog, err error) {
log.EXPECT().Errorf("user registration: tx begin: %s", err.Error())
},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedErr: domain.InternalServerError,
},
{
name: "get_error",
mockParams: mockParams{
rows: dbRows,
err: errors.New("some error"),
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin()
p.mock.ExpectQuery(
`INSERT INTO users \(email, hashed_password, username, date_of_birth\) VALUES \(\$1, \$2, \$3, \$4\) RETURNING \*`,
).WithArgs(p.email, p.hashedPassword, p.username, p.dateOfBirth).WillReturnError(p.err)
p.mock.ExpectRollback()
},
logBehavior: func(log *mock_logger.MockLog, err error) {
log.EXPECT().Errorf("user registration: %s", err.Error())
},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedErr: domain.InternalServerError,
},
{
name: "exec_error",
mockParams: mockParams{
rows: dbRows,
err: errors.New("some error"),
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin()
p.mock.ExpectQuery(
`INSERT INTO users \(email, hashed_password, username, date_of_birth\) VALUES \(\$1, \$2, \$3, \$4\) RETURNING \*`,
).WithArgs(p.email, p.hashedPassword, p.username, p.dateOfBirth).WillReturnRows(p.rows)
p.mock.ExpectExec(
`INSERT INTO user_avatar \(user_id, avatar_image\) VALUES \(\$1, \$2\)`,
).WithArgs(p.userID, p.avatarImage).WillReturnError(p.err)
p.mock.ExpectRollback()
},
logBehavior: func(log *mock_logger.MockLog, err error) {
log.EXPECT().Errorf("user registration: %s", err.Error())
},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedErr: domain.InternalServerError,
},
{
name: "commit_error",
mockParams: mockParams{
rows: dbRows,
err: errors.New("some error"),
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin()
p.mock.ExpectQuery(
`INSERT INTO users \(email, hashed_password, username, date_of_birth\) VALUES \(\$1, \$2, \$3, \$4\) RETURNING \*`,
).WithArgs(p.email, p.hashedPassword, p.username, p.dateOfBirth).WillReturnRows(p.rows)
p.mock.ExpectExec(
`INSERT INTO user_avatar \(user_id, avatar_image\) VALUES \(\$1, \$2\)`,
).WithArgs(p.userID, p.avatarImage).WillReturnResult(sqlmock.NewResult(1, 1))
p.mock.ExpectCommit().WillReturnError(p.err)
// p.mock.ExpectRollback().WillReturnError(sql.ErrTxDone) // с ним падает тест тк вызов роллбека не доходит
// до драйвера и он его не регистрирует
},
logBehavior: func(log *mock_logger.MockLog, err error) {
log.EXPECT().Errorf("user registration: %s", err.Error())
},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedErr: domain.InternalServerError,
},
{
name: "rollback_error",
mockParams: mockParams{
rows: dbRows,
err: database.IntegrityError,
},
mockBehavior: func(p mockParams) {
p.mock.ExpectBegin()
p.mock.ExpectQuery(
`INSERT INTO users \(email, hashed_password, username, date_of_birth\) VALUES \(\$1, \$2, \$3, \$4\) RETURNING \*`,
).WithArgs(p.email, p.hashedPassword, p.username, p.dateOfBirth).WillReturnError(p.err)
p.mock.ExpectRollback().WillReturnError(p.err)
},
logBehavior: func(log *mock_logger.MockLog, err error) {
log.EXPECT().Errorf("user registration: tx rollback: %s", err.Error())
},
ud: domain.User{
ID: 1,
Role: 1,
Username: "urec",
Email: "mail@mail.ru",
HashedPassword: "hp",
AvatarImage: "image",
BlackPhoenix: false,
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
DateOfRegistration: domain.CustomDate{Time: time.Date(2025, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
expectedErr: domain.UserAlreadyExistsError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
db, mock, dbClose := database.GetMockDBx(t)
defer dbClose()
log := mock_logger.NewMockLog(c)
tc.mockParams.mock = mock
tc.mockParams.rows.AddRow(
tc.ud.ID,
tc.ud.Role,
tc.ud.Username,
tc.ud.Email,
tc.ud.HashedPassword,
tc.ud.AvatarImage,
tc.ud.BlackPhoenix,
tc.ud.DateOfBirth,
tc.ud.DateOfRegistration,
)
tc.mockParams.email = tc.ud.Email
tc.mockParams.hashedPassword = tc.ud.HashedPassword
tc.mockParams.username = tc.ud.Username
tc.mockParams.avatarImage = tc.ud.AvatarImage
tc.mockParams.dateOfBirth = tc.ud.DateOfBirth.Time
tc.mockParams.userID = tc.ud.ID
tc.mockBehavior(tc.mockParams)
tc.logBehavior(log, tc.mockParams.err)
repo := &userRepository{db: db, l: log}
u, err := repo.Register(tc.mockParams.email, tc.mockParams.hashedPassword, tc.mockParams.username, tc.mockParams.dateOfBirth)
assert.Equal(t, tc.expectedUser, u)
assert.ErrorIs(t, err, tc.expectedErr)
assert.NoError(t, tc.mockParams.mock.ExpectationsWereMet())
})
}
}