chat_back_go/internal/repository/users_test.go

671 lines
20 KiB
Go
Raw Permalink 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/config"
"git.urec56.ru/urec/chat_back_go/internal/database"
mock_database "git.urec56.ru/urec/chat_back_go/internal/database/mocks"
"git.urec56.ru/urec/chat_back_go/internal/domain"
"git.urec56.ru/urec/chat_back_go/internal/logger"
)
func Test_newUser(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
db, _, dbClose := mock_database.GetMockDBx(t)
defer dbClose()
log := logger.NewLogger(config.Config{Mode: "TEST"})
repo := newUserRepo(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 := mock_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)
testTable := []struct {
name string
username string
mockBehavior mockBehavior
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)
},
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)
},
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 := mock_database.GetMockDBx(t)
defer dbClose()
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)
log := logger.NewLogger(config.Config{Mode: "TEST"})
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 := mock_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)
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
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()
},
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()
},
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)
},
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()
},
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()
},
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) // с ним падает тест тк вызов роллбека не доходит
// до драйвера и он его не регистрирует
},
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)
},
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 := mock_database.GetMockDBx(t)
defer dbClose()
log := logger.NewLogger(config.Config{Mode: "TEST"})
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)
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())
})
}
}