chat_back_go/internal/transport/rest/handler/users_test.go

592 lines
17 KiB
Go

package handler
import (
"bytes"
"context"
"encoding/json"
"errors"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"io"
"net/http"
"net/http/httptest"
"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_service "git.urec56.ru/urec/chat_back_go/internal/service/mocks"
mock_http "git.urec56.ru/urec/chat_back_go/internal/transport/rest/handler/mocks"
)
func TestHandler_GetUsers(t *testing.T) {
type servBehavior func(s *mock_service.MockServ, username string, users []domain.User, err error)
testTable := []struct {
name string
username string
servBehavior servBehavior
servUsers []domain.User
servErr error
logErr error
writeErr error
expectedUsers map[string][]domain.User
expectedStatusCode int
}{
{
name: "ok_1",
username: "urec",
servBehavior: func(s *mock_service.MockServ, username string, users []domain.User, err error) {
s.EXPECT().GetAll(username).Return(users, err)
},
servUsers: []domain.User{
{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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: map[string][]domain.User{
"users": {
{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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)},
},
},
},
expectedStatusCode: http.StatusOK,
},
{
name: "ok_2",
servBehavior: func(s *mock_service.MockServ, username string, users []domain.User, err error) {
s.EXPECT().GetAll(username).Return(users, err)
},
servUsers: []domain.User{
{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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: map[string][]domain.User{
"users": {
{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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)},
},
},
},
expectedStatusCode: http.StatusOK,
},
{
name: "serv_error",
servBehavior: func(s *mock_service.MockServ, username string, users []domain.User, err error) {
s.EXPECT().GetAll(username).Return(users, err)
},
servErr: domain.AnyError,
logErr: domain.AnyError,
expectedStatusCode: http.StatusInternalServerError,
},
{
name: "response_writing_error",
servBehavior: func(s *mock_service.MockServ, username string, users []domain.User, err error) {
s.EXPECT().GetAll(username).Return(users, err)
},
logErr: domain.AnyError,
writeErr: domain.AnyError,
expectedStatusCode: http.StatusInternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
reqPath := "/users"
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
tc.servBehavior(serv, tc.username, tc.servUsers, tc.servErr)
req := httptest.NewRequest(http.MethodGet, reqPath, nil)
w := mock_http.NewRecorder(tc.writeErr)
q := req.URL.Query()
q.Add("username", tc.username)
req.URL.RawQuery = q.Encode()
h := &Handler{serv: serv, l: log}
h.GetUsers(w, req)
resp := w.Result()
b, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
var u map[string][]domain.User
if tc.expectedStatusCode == http.StatusOK {
err = json.Unmarshal(b, &u)
assert.NoError(t, err)
}
assert.Equal(t, tc.expectedUsers, u)
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
})
}
}
func TestHandler_CheckExisting(t *testing.T) {
type servBehavior func(s *mock_service.MockServ, username, email string, user domain.User, err error)
testTable := []struct {
name string
reqBody domain.UserFilter
servBehavior servBehavior
servUser domain.User
servErr error
logErr error
isDecodeError bool
expectedStatusCode int
}{
{
name: "ok",
reqBody: domain.UserFilter{Username: "urecs", Email: "mail@atod.com"},
servBehavior: func(s *mock_service.MockServ, username, email string, user domain.User, err error) {
s.EXPECT().FindOne(username, email).Return(user, err)
},
expectedStatusCode: http.StatusOK,
},
{
name: "decoding_body_error",
servBehavior: func(s *mock_service.MockServ, username, email string, user domain.User, err error) {},
isDecodeError: true,
expectedStatusCode: http.StatusUnprocessableEntity,
},
{
name: "validation_error",
reqBody: domain.UserFilter{Username: "u"},
servBehavior: func(s *mock_service.MockServ, username, email string, user domain.User, err error) {},
logErr: errors.New("Key: 'UserFilter.Username' Error:Field validation for 'Username' failed on the 'min' tag"),
expectedStatusCode: http.StatusUnprocessableEntity,
},
{
name: "serv_error",
reqBody: domain.UserFilter{Username: "urec"},
servBehavior: func(s *mock_service.MockServ, username, email string, user domain.User, err error) {
s.EXPECT().FindOne(username, email).Return(user, err)
},
servErr: domain.AnyError,
logErr: domain.AnyError,
expectedStatusCode: http.StatusInternalServerError,
},
{
name: "user_already_exists",
reqBody: domain.UserFilter{Username: "urec"},
servUser: domain.User{ID: 1},
servBehavior: func(s *mock_service.MockServ, username, email string, user domain.User, err error) {
s.EXPECT().FindOne(username, email).Return(user, err)
},
expectedStatusCode: http.StatusConflict,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
reqPath := "/check_existing_user"
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
tc.servBehavior(serv, tc.reqBody.Username, tc.reqBody.Email, tc.servUser, tc.servErr)
var body []byte
if !tc.isDecodeError {
b, err := json.Marshal(tc.reqBody)
assert.NoError(t, err)
body = b
} else {
b := make([]byte, 0)
body = b
}
req := httptest.NewRequest(http.MethodPost, reqPath, bytes.NewBuffer(body))
w := mock_http.NewRecorder(nil)
h := &Handler{serv: serv, l: log}
h.CheckExisting(w, req)
resp := w.Result()
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
})
}
}
func TestHandler_CheckExistingPassword(t *testing.T) {
reqPath := "/check_existing_password"
req := httptest.NewRequest(http.MethodPost, reqPath, nil)
w := httptest.NewRecorder()
h := &Handler{}
for i := 0; i < 10; i++ {
h.CheckExistingPassword(w, req)
}
}
func TestHandler_Register(t *testing.T) {
type servBehavior func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error)
testTable := []struct {
name string
reqBody domain.UserRegister
servBehavior servBehavior
servToken string
servErr error
logErr error
isDecodeError bool
writeErr error
expectedStatusCode int
expectedBody map[string]string
}{
{
name: "ok",
reqBody: domain.UserRegister{
Username: "urecs",
Email: "mail@atod.com",
Password: "password",
Password2: "password",
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
servBehavior: func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error) {
s.EXPECT().Register(userData).Return(token, err)
},
servToken: "token",
expectedStatusCode: http.StatusCreated,
expectedBody: map[string]string{"authorization": "Bearer token"},
},
{
name: "user_already_exists",
reqBody: domain.UserRegister{
Username: "urec",
Email: "mail@atod.com",
Password: "password",
Password2: "password",
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
servBehavior: func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error) {
s.EXPECT().Register(userData).Return(token, err)
},
servErr: domain.UserAlreadyExistsError,
expectedStatusCode: http.StatusConflict,
},
{
name: "decoding_body_error",
servBehavior: func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error) {},
isDecodeError: true,
expectedStatusCode: http.StatusUnprocessableEntity,
},
{
name: "validation_error",
reqBody: domain.UserRegister{
Email: "mail@atod.com",
Password: "password",
Password2: "password",
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
servBehavior: func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error) {},
logErr: errors.New("Key: 'UserRegister.Username' Error:Field validation for 'Username' failed on the 'min' tag"),
expectedStatusCode: http.StatusUnprocessableEntity,
},
{
name: "serv_error",
reqBody: domain.UserRegister{
Username: "urec",
Email: "mail@atod.com",
Password: "password",
Password2: "password",
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
servBehavior: func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error) {
s.EXPECT().Register(userData).Return(token, err)
},
servErr: domain.AnyError,
logErr: domain.AnyError,
expectedStatusCode: http.StatusInternalServerError,
},
{
name: "response_writing_error",
reqBody: domain.UserRegister{
Username: "urec",
Email: "mail@atod.com",
Password: "password",
Password2: "password",
DateOfBirth: domain.CustomDate{Time: time.Date(2002, time.February, 2, 0, 0, 0, 0, time.UTC)},
},
servBehavior: func(s *mock_service.MockServ, userData domain.UserRegister, token string, err error) {
s.EXPECT().Register(userData).Return(token, err)
},
writeErr: domain.AnyError,
logErr: domain.AnyError,
expectedStatusCode: http.StatusCreated,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
reqPath := "/register"
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
tc.servBehavior(serv, tc.reqBody, tc.servToken, tc.servErr)
var body []byte
if !tc.isDecodeError {
b, err := json.Marshal(tc.reqBody)
assert.NoError(t, err)
body = b
} else {
b := make([]byte, 0)
body = b
}
req := httptest.NewRequest(http.MethodPost, reqPath, bytes.NewBuffer(body))
w := mock_http.NewRecorder(tc.writeErr)
h := &Handler{serv: serv, l: log}
h.Register(w, req)
resp := w.Result()
b, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
var authToken map[string]string
if tc.expectedStatusCode == http.StatusCreated && tc.writeErr == nil {
err = json.Unmarshal(b, &authToken)
assert.NoError(t, err)
}
assert.Equal(t, tc.expectedBody, authToken)
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
})
}
}
func TestHandler_ResendEmailVerification(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
req := httptest.NewRequest("", "/chats", nil)
w := httptest.NewRecorder()
h := &Handler{serv: serv, l: log}
h.ResendEmailVerification(w, req)
_ = w.Result()
}
func TestHandler_EmailVerification(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
req := httptest.NewRequest("", "/chats", nil)
w := httptest.NewRecorder()
h := &Handler{serv: serv, l: log}
h.EmailVerification(w, req)
_ = w.Result()
}
func TestHandler_Login(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
req := httptest.NewRequest("", "/chats", nil)
w := httptest.NewRecorder()
h := &Handler{serv: serv, l: log}
h.Login(w, req)
_ = w.Result()
}
func TestHandler_Get(t *testing.T) {
testTable := []struct {
name string
ctxUser domain.User
addingCtxUser bool
logErr error
writeErr error
expectedUser domain.User
expectedStatusCode int
}{
{
name: "ok",
ctxUser: domain.User{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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)},
},
addingCtxUser: true,
expectedUser: domain.User{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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)},
},
expectedStatusCode: http.StatusOK,
},
{
name: "incorrect_user_in_ctx",
expectedStatusCode: http.StatusInternalServerError,
},
{
name: "response_writing_error",
ctxUser: domain.User{
ID: 1,
Username: "urec",
Email: "mail@mail.ru",
AvatarImage: "image",
BlackPhoenix: true,
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)},
},
addingCtxUser: true,
logErr: domain.AnyError,
writeErr: domain.AnyError,
expectedStatusCode: http.StatusInternalServerError,
},
}
for _, tc := range testTable {
t.Run(tc.name, func(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
reqPath := "/users/me"
log := logger.NewLogger(config.Config{Mode: "TEST"})
req := httptest.NewRequest(http.MethodGet, reqPath, nil)
w := mock_http.NewRecorder(tc.writeErr)
ctx := req.Context()
if tc.addingCtxUser {
ctx = context.WithValue(ctx, "user", tc.ctxUser)
}
req = req.WithContext(ctx)
h := &Handler{l: log}
h.Get(w, req)
resp := w.Result()
b, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
var u domain.User
if tc.expectedStatusCode == http.StatusOK {
err = json.Unmarshal(b, &u)
assert.NoError(t, err)
}
assert.Equal(t, tc.expectedUser, u)
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
})
}
}
func TestHandler_GetAvatarsHistory(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
req := httptest.NewRequest("", "/chats", nil)
w := httptest.NewRecorder()
h := &Handler{serv: serv, l: log}
h.GetAvatarsHistory(w, req)
_ = w.Result()
}
func TestHandler_SendConfirmationCode(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
req := httptest.NewRequest("", "/chats", nil)
w := httptest.NewRecorder()
h := &Handler{serv: serv, l: log}
h.SendConfirmationCode(w, req)
_ = w.Result()
}
func TestHandler_ChangeUserData(t *testing.T) {
c := gomock.NewController(t)
defer c.Finish()
log := logger.NewLogger(config.Config{Mode: "TEST"})
serv := mock_service.NewMockServ(c)
req := httptest.NewRequest("", "/chats", nil)
w := httptest.NewRecorder()
h := &Handler{serv: serv, l: log}
h.ChangeUserData(w, req)
_ = w.Result()
}