429 lines
11 KiB
Go
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)
|
||
|
})
|
||
|
}
|