ms-auth/internal/users/delivery/grpc/handlers_test.go
Vyacheslav1557 3b03447d2f feat(user):
2024-12-30 20:04:26 +05:00

429 lines
11 KiB
Go

package grpc
import (
"context"
"git.sch9.ru/new_gate/ms-auth/internal/models"
"git.sch9.ru/new_gate/ms-auth/internal/users"
mock_users "git.sch9.ru/new_gate/ms-auth/internal/users/delivery/mock"
userv1 "git.sch9.ru/new_gate/ms-auth/proto/user/v1"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"golang.org/x/crypto/bcrypt"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"net"
"testing"
"time"
)
func startServer(t *testing.T, uc users.UseCase, addr string) {
t.Helper()
gserver := grpc.NewServer()
NewUserHandlers(gserver, uc)
ln, err := net.Listen("tcp", addr)
if err != nil {
panic(err)
}
go func() {
if err = gserver.Serve(ln); err != nil {
panic(err)
}
}()
t.Cleanup(func() {
gserver.Stop()
})
}
func buildClient(t *testing.T, addr string) userv1.UserServiceClient {
t.Helper()
conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
require.NoError(t, err)
return userv1.NewUserServiceClient(conn)
}
func TestUserHandlers_Login(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62999"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid login", func(t *testing.T) {
password := "password"
hpwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
require.NoError(t, err)
user := &models.User{
Id: 1,
Username: "username",
HashedPassword: string(hpwd),
Role: models.RoleAdmin,
}
sid := uuid.NewString()
uc.EXPECT().ReadUserByUsername(gomock.Any(), user.Username).Return(user, nil)
uc.EXPECT().CreateSession(gomock.Any(), user.Id, user.Role).Return(sid, nil)
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
var header metadata.MD
_, err = client.Login(ctx, &userv1.LoginRequest{
Username: user.Username,
Password: password,
}, grpc.Header(&header))
require.NoError(t, err)
require.Equal(t, sid, header.Get(SessionHeaderName)[0])
})
t.Run("invalid login (wrong password)", func(t *testing.T) {
password := "password"
hpwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
require.NoError(t, err)
user := &models.User{
Id: 1,
Username: "username",
HashedPassword: string(hpwd),
Role: models.RoleAdmin,
}
uc.EXPECT().ReadUserByUsername(gomock.Any(), user.Username).Return(user, nil)
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err = client.Login(ctx, &userv1.LoginRequest{
Username: user.Username,
Password: "wrongpassword",
})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.NotFound, s.Code())
})
}
func TestUserHandlers_Refresh(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62998"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid refresh", func(t *testing.T) {
sid := uuid.NewString()
uc.EXPECT().UpdateSession(gomock.Any(), sid).Return(nil)
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, sid)
_, err := client.Refresh(ctx, &emptypb.Empty{})
require.NoError(t, err)
})
t.Run("invalid refresh (no session id in context)", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err := client.Refresh(ctx, &emptypb.Empty{})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Unauthenticated, s.Code())
})
}
func TestUserHandlers_Logout(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62997"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid logout", func(t *testing.T) {
sid := uuid.NewString()
uc.EXPECT().DeleteSession(gomock.Any(), sid).Return(nil)
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, sid)
_, err := client.Logout(ctx, &emptypb.Empty{})
require.NoError(t, err)
})
t.Run("invalid logout (no session id in context)", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err := client.Logout(ctx, &emptypb.Empty{})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Unauthenticated, s.Code())
})
}
func TestUserHandlers_CompleteLogout(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62996"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid complete logout", func(t *testing.T) {
sid := uuid.NewString()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, sid)
t.Cleanup(cancel)
uc.EXPECT().ReadSession(gomock.Any(), sid).Return(&models.Session{UserId: 1}, nil)
uc.EXPECT().DeleteAllSessions(gomock.Any(), int32(1)).Return(nil)
_, err := client.CompleteLogout(ctx, &emptypb.Empty{})
require.NoError(t, err)
})
t.Run("invalid complete logout (no session id in context)", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err := client.CompleteLogout(ctx, &emptypb.Empty{})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Unauthenticated, s.Code())
})
}
func TestUserHandlers_Verify(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62995"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid verify", func(t *testing.T) {
sid := uuid.NewString()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, sid)
t.Cleanup(cancel)
uc.EXPECT().Verify(gomock.Any(), sid).Return("jwt", nil)
var header metadata.MD
_, err := client.Verify(ctx, &emptypb.Empty{}, grpc.Header(&header))
require.NoError(t, err)
require.Equal(t, header.Get(AuthUserHeaderName)[0], "jwt")
})
t.Run("invalid verify (no session id in context)", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err := client.Verify(ctx, &emptypb.Empty{})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Unauthenticated, s.Code())
})
}
func TestUserHandlers_CreateUser(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62994"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid create user", func(t *testing.T) {
username := "username"
password := "password"
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, uuid.NewString())
t.Cleanup(cancel)
uc.EXPECT().CreateUser(gomock.Any(), username, password, models.RoleParticipant).Return(int32(2), nil)
_, err := client.CreateUser(ctx, &userv1.CreateUserRequest{
Username: username,
Password: password,
})
require.NoError(t, err)
})
t.Run("invalid create user (no session id in context)", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err := client.CreateUser(ctx, &userv1.CreateUserRequest{
Username: "username",
Password: "password",
})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Unauthenticated, s.Code())
})
}
func TestUserHandlers_GetUser(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62993"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid get user", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
uc.EXPECT().ReadUserById(gomock.Any(), int32(1)).Return(&models.User{
Id: 1,
Username: "username",
CreatedAt: time.Now(),
ModifiedAt: time.Now(),
Role: models.RoleParticipant,
}, nil)
_, err := client.GetUser(ctx, &userv1.GetUserRequest{
Id: 1,
})
require.NoError(t, err)
})
}
func TestUserHandlers_UpdateUser(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62992"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid update user", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, uuid.NewString())
t.Cleanup(cancel)
uc.EXPECT().UpdateUser(gomock.Any(),
int32(1),
AsStringP("username"),
AsRoleP(models.RoleModerator),
).Return(nil)
_, err := client.UpdateUser(ctx, &userv1.UpdateUserRequest{
Id: 1,
Username: "username",
Role: userv1.Role_ROLE_MODERATOR,
})
require.NoError(t, err)
})
t.Run("invalid update user (no session id in context)", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
t.Cleanup(cancel)
_, err := client.UpdateUser(ctx, &userv1.UpdateUserRequest{
Id: 1,
Username: "username",
Role: userv1.Role_ROLE_MODERATOR,
})
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Unauthenticated, s.Code())
})
}
func TestUserHandlers_DeleteUser(t *testing.T) {
t.Parallel()
const addr = "127.0.0.1:62991"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
uc := mock_users.NewMockUseCase(ctrl)
startServer(t, uc, addr)
client := buildClient(t, addr)
t.Run("valid delete user", func(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
ctx = metadata.AppendToOutgoingContext(ctx, SessionHeaderName, uuid.NewString())
t.Cleanup(cancel)
uc.EXPECT().DeleteUser(gomock.Any(), int32(1)).Return(nil)
_, err := client.DeleteUser(ctx, &userv1.DeleteUserRequest{
Id: 1,
})
require.NoError(t, err)
})
}