chat_back_go/internal/service/users_test.go

462 lines
16 KiB
Go

package service
import (
"encoding"
"errors"
"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/domain"
"git.urec56.ru/urec/chat_back_go/internal/logger"
mock_repository "git.urec56.ru/urec/chat_back_go/internal/repository/mocks"
mock_service "git.urec56.ru/urec/chat_back_go/internal/service/mocks"
)
func Test_newUserService(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
repo := mock_repository.NewMockUser(c)
auth := mock_service.NewMockAuth(c)
log := logger.NewLogger(config.Config{Mode: "TEST"})
cache := mock_service.NewMockCache(c)
serv := newUserService(repo, auth, log, cache)
assert.EqualValues(t, &userService{ur: repo, auth: auth, l: log, cache: cache}, serv)
}
func TestUserService_Get(t *testing.T) {
type repoBehavior func(r *mock_repository.MockUser, userID int, user domain.User, err error)
type cacheGetBehavior func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error)
type cacheSetBehavior func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error)
type cacheGetData struct {
container *domain.User
err error
}
type cacheSetData struct {
value domain.User
duration time.Duration
err error
}
testTable := []struct {
name string
repoBehavior repoBehavior
cacheGetBehavior cacheGetBehavior
cacheSetBehavior cacheSetBehavior
cacheKey string
cacheGetData cacheGetData
cacheSetData cacheSetData
userID int
repoUser domain.User
repoErr error
logErr1 error
logErr2 error
expectedUser domain.User
expectedErr error
}{
{
name: "user_in_cache",
repoBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {},
cacheGetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error) {
c.EXPECT().Get(key, gomock.Any(), false).DoAndReturn(
func(key string, v encoding.BinaryUnmarshaler, isFast bool) error {
return v.UnmarshalBinary([]byte(`{"id": 1}`))
},
)
},
cacheSetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error) {},
cacheKey: "user: {'id': 1}",
cacheGetData: cacheGetData{container: &domain.User{}},
userID: 1,
expectedUser: domain.User{ID: 1},
},
{
name: "no_user_in_cache",
repoBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
cacheGetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error) {
c.EXPECT().Get(key, gomock.Any(), false).Return(err)
},
cacheSetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error) {
c.EXPECT().Set(key, v, ex).Return(err)
},
cacheKey: "user: {'id': 1}",
cacheGetData: cacheGetData{container: &domain.User{}, err: domain.NoKeyFoundError},
cacheSetData: cacheSetData{value: domain.User{ID: 1}, duration: time.Second * 20},
logErr1: domain.NoKeyFoundError,
userID: 1,
repoUser: domain.User{ID: 1},
expectedUser: domain.User{ID: 1},
},
{
name: "user_not_found",
repoBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
cacheGetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error) {
c.EXPECT().Get(key, gomock.Any(), false).Return(err)
},
cacheSetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error) {},
cacheKey: "user: {'id': 1}",
cacheGetData: cacheGetData{container: &domain.User{}, err: domain.NoKeyFoundError},
logErr1: domain.NoKeyFoundError,
userID: 1,
repoErr: domain.UserNotFoundError,
expectedErr: domain.UserNotFoundError,
},
{
name: "cache_get_error",
repoBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
cacheGetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error) {
c.EXPECT().Get(key, gomock.Any(), false).Return(err)
},
cacheSetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error) {
c.EXPECT().Set(key, v, ex).Return(err)
},
cacheKey: "user: {'id': 1}",
cacheGetData: cacheGetData{container: &domain.User{}, err: domain.InternalServerError},
cacheSetData: cacheSetData{value: domain.User{ID: 1}, duration: time.Second * 20},
logErr1: domain.InternalServerError,
userID: 1,
repoUser: domain.User{ID: 1},
expectedUser: domain.User{ID: 1},
},
{
name: "cache_set_error",
repoBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
cacheGetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error) {
c.EXPECT().Get(key, gomock.Any(), false).Return(err)
},
cacheSetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error) {
c.EXPECT().Set(key, v, ex).Return(err)
},
cacheKey: "user: {'id': 1}",
cacheGetData: cacheGetData{container: &domain.User{}, err: domain.NoKeyFoundError},
cacheSetData: cacheSetData{value: domain.User{ID: 1}, duration: time.Second * 20, err: domain.InternalServerError},
logErr1: domain.NoKeyFoundError,
logErr2: domain.InternalServerError,
userID: 1,
repoUser: domain.User{ID: 1},
expectedUser: domain.User{ID: 1},
},
{
name: "repo_error",
repoBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
cacheGetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryUnmarshaler, err error) {
c.EXPECT().Get(key, gomock.Any(), false).Return(err)
},
cacheSetBehavior: func(c *mock_service.MockCache, key string, v encoding.BinaryMarshaler, ex time.Duration, err error) {},
cacheKey: "user: {'id': 1}",
cacheGetData: cacheGetData{container: &domain.User{}, err: domain.NoKeyFoundError},
logErr1: domain.NoKeyFoundError,
userID: 1,
repoErr: domain.InternalServerError,
expectedErr: domain.InternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
repo := mock_repository.NewMockUser(c)
cache := mock_service.NewMockCache(c)
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := userService{ur: repo, l: log, cache: cache}
tc.repoBehavior(repo, tc.userID, tc.repoUser, tc.repoErr)
tc.cacheGetBehavior(cache, tc.cacheKey, tc.cacheGetData.container, tc.cacheGetData.err)
tc.cacheSetBehavior(cache, tc.cacheKey, &tc.cacheSetData.value, tc.cacheSetData.duration, tc.cacheSetData.err)
u, err := serv.Get(tc.userID, false)
assert.Equal(t, tc.expectedUser, u)
assert.ErrorIs(t, err, tc.expectedErr)
})
}
}
func TestUserService_GetVerificated(t *testing.T) {
type mockBehavior func(r *mock_repository.MockUser, userID int, user domain.User, err error)
testTable := []struct {
name string
mockBehavior mockBehavior
userID int
expectedUser domain.User
repoErr error
expectedErr error
}{
{
name: "ok",
mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
userID: 1,
expectedUser: domain.User{
ID: 1,
Role: domain.VerificatedUser,
},
},
{
name: "user_not_found",
mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
userID: 1,
repoErr: domain.UserNotFoundError,
expectedErr: domain.UserNotFoundError,
},
{
name: "user_unverified",
mockBehavior: func(r *mock_repository.MockUser, userID int, user domain.User, err error) {
r.EXPECT().GetByID(userID).Return(user, err)
},
userID: 1,
expectedUser: domain.User{
ID: 1,
Role: domain.UnverifiedUser,
},
expectedErr: domain.UnverifiedUserError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
repo := mock_repository.NewMockUser(c)
serv := userService{ur: repo}
tc.mockBehavior(repo, tc.userID, tc.expectedUser, tc.repoErr)
u, err := serv.GetVerificated(tc.userID)
assert.Equal(t, tc.expectedUser, u)
assert.ErrorIs(t, err, tc.expectedErr)
})
}
}
func TestUserService_GetAll(t *testing.T) {
type mockBehavior func(r *mock_repository.MockUser, username string, users []domain.User, err error)
testTable := []struct {
name string
mockBehavior mockBehavior
username string
expectedUsers []domain.User
repoErr error
expectedErr error
}{
{
name: "ok",
mockBehavior: func(r *mock_repository.MockUser, username string, users []domain.User, err error) {
r.EXPECT().GetAll(username).Return(users, err)
},
expectedUsers: []domain.User{
{ID: 1},
},
},
{
name: "internal_error",
mockBehavior: func(r *mock_repository.MockUser, username string, users []domain.User, err error) {
r.EXPECT().GetAll(username).Return(users, err)
},
repoErr: domain.InternalServerError,
expectedErr: domain.InternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
repo := mock_repository.NewMockUser(c)
serv := userService{ur: repo}
tc.mockBehavior(repo, tc.username, tc.expectedUsers, tc.repoErr)
u, err := serv.GetAll(tc.username)
assert.Equal(t, tc.expectedUsers, u)
assert.ErrorIs(t, err, tc.expectedErr)
})
}
}
func TestUserService_FindOne(t *testing.T) {
type mockBehavior func(r *mock_repository.MockUser, username, email string, user domain.User, err error)
testTable := []struct {
name string
mockBehavior mockBehavior
username string
email string
expectedUser domain.User
repoErr error
expectedErr error
}{
{
name: "ok",
mockBehavior: func(r *mock_repository.MockUser, username, email string, user domain.User, err error) {
r.EXPECT().FindOne(username, email).Return(user, err)
},
expectedUser: domain.User{
ID: 1,
Role: domain.UnverifiedUser,
},
},
{
name: "any_error",
mockBehavior: func(r *mock_repository.MockUser, username, email string, user domain.User, err error) {
r.EXPECT().FindOne(username, email).Return(user, err)
},
repoErr: 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()
repo := mock_repository.NewMockUser(c)
serv := userService{ur: repo}
tc.mockBehavior(repo, tc.username, tc.email, tc.expectedUser, tc.repoErr)
u, err := serv.FindOne(tc.username, tc.email)
assert.Equal(t, tc.expectedUser, u)
assert.ErrorIs(t, err, tc.expectedErr)
})
}
}
func TestUserService_Register(t *testing.T) {
type hashMockBehavior func(s *mock_service.MockAuth, p, hp string, err error)
type repoMockBehavior func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error)
type encodeMockBehavior func(s *mock_service.MockAuth, userID int, token string, err error)
testTable := []struct {
name string
hashMockBehavior hashMockBehavior
repoMockBehavior repoMockBehavior
encodeMockBehavior encodeMockBehavior
ud domain.UserRegister
hp string
repoUser domain.User
hashErr error
repoErr error
encodeErr error
expectedToken string
expectedErr error
}{
{
name: "ok",
hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) {
s.EXPECT().HashPassword(p).Return(hp, err)
},
repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) {
r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err)
},
encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {
s.EXPECT().EncodeAuthToken(userID).Return(token, err)
},
ud: domain.UserRegister{
Email: "mail@mail.ru",
Username: "username",
Password: "pass",
},
hp: "hp",
repoUser: domain.User{ID: 1},
expectedToken: "token",
},
{
name: "user_already_exists",
hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) {
s.EXPECT().HashPassword(p).Return(hp, err)
},
repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) {
r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err)
},
encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {},
repoErr: domain.UserAlreadyExistsError,
expectedErr: domain.UserAlreadyExistsError,
},
{
name: "hash_failed",
hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) {
s.EXPECT().HashPassword(p).Return(hp, err)
},
repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) {
},
encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {},
hashErr: errors.New("some error"),
expectedErr: domain.InternalServerError,
},
{
name: "db_error",
hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) {
s.EXPECT().HashPassword(p).Return(hp, err)
},
repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) {
r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err)
},
encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {},
repoErr: errors.New("some error"),
expectedErr: domain.InternalServerError,
},
{
name: "token_encoding_error",
hashMockBehavior: func(s *mock_service.MockAuth, p, hp string, err error) {
s.EXPECT().HashPassword(p).Return(hp, err)
},
repoMockBehavior: func(r *mock_repository.MockUser, email, hp, username string, dateOfBirth time.Time, user domain.User, err error) {
r.EXPECT().Register(email, hp, username, dateOfBirth).Return(user, err)
},
encodeMockBehavior: func(s *mock_service.MockAuth, userID int, token string, err error) {
s.EXPECT().EncodeAuthToken(userID).Return(token, err)
},
encodeErr: 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()
repo := mock_repository.NewMockUser(c)
auth := mock_service.NewMockAuth(c)
serv := userService{ur: repo, auth: auth}
tc.hashMockBehavior(auth, tc.ud.Password, tc.hp, tc.hashErr)
tc.repoMockBehavior(repo, tc.ud.Email, tc.hp, tc.ud.Username, tc.ud.DateOfBirth.Time, tc.repoUser, tc.repoErr)
tc.encodeMockBehavior(auth, tc.repoUser.ID, tc.expectedToken, tc.encodeErr)
token, err := serv.Register(tc.ud)
assert.Equal(t, tc.expectedToken, token)
assert.ErrorIs(t, err, tc.expectedErr)
})
}
}