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

612 lines
16 KiB
Go

package usecase
import (
"context"
"git.sch9.ru/new_gate/ms-auth/config"
"git.sch9.ru/new_gate/ms-auth/internal/models"
mock_users "git.sch9.ru/new_gate/ms-auth/internal/users/usecase/mock"
"git.sch9.ru/new_gate/ms-auth/pkg"
"github.com/golang-jwt/jwt/v4"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"testing"
)
func TestUseCase_CreateUser(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
pgRepository := mock_users.NewMockPgRepository(ctrl)
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
caller := mock_users.NewMockCaller(ctrl)
uc := NewUseCase(
pgRepository,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid create user (admin > moderator)", func(t *testing.T) {
userId := int32(1)
username := "username"
password := "password"
role := models.RoleModerator
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).Times(2)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleAdmin,
}, nil)
caller.EXPECT().CreateUser(ctx, username, password, role).Return(int32(2), nil)
id, err := uc.CreateUser(ctx, username, password, role)
require.NoError(t, err)
require.Equal(t, int32(2), id)
})
t.Run("valid create user (moderator > participant)", func(t *testing.T) {
userId := int32(1)
username := "username"
password := "password"
role := models.RoleParticipant
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).Times(2)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleModerator,
}, nil)
caller.EXPECT().CreateUser(ctx, username, password, role).Return(int32(2), nil)
id, err := uc.CreateUser(ctx, username, password, role)
require.NoError(t, err)
require.Equal(t, int32(2), id)
})
t.Run("valid create user (admin > participant)", func(t *testing.T) {
userId := int32(1)
username := "username"
password := "password"
role := models.RoleParticipant
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).Times(2)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleAdmin,
}, nil)
caller.EXPECT().CreateUser(ctx, username, password, role).Return(int32(2), nil)
id, err := uc.CreateUser(ctx, username, password, role)
require.NoError(t, err)
require.Equal(t, int32(2), id)
})
t.Run("invalid user create 1 (no user id in context)", func(t *testing.T) {
_, err := uc.CreateUser(context.Background(), "username", "password", models.RoleModerator)
require.Error(t, err)
require.ErrorIs(t, err, pkg.ErrUnauthenticated)
})
t.Run("invalid user create 2 (user not found)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserById(ctx, userId).Return(nil, pkg.ErrNotFound)
_, err := uc.CreateUser(ctx, "username", "password", models.RoleModerator)
require.Error(t, err)
require.ErrorIs(t, err, pkg.ErrNotFound)
})
t.Run("invalid user create 3 (no permission, participant < admin)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleParticipant,
}, nil)
_, err := uc.CreateUser(ctx, "username", "password", models.RoleAdmin)
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
t.Run("invalid user create 4 (no permission, participant < moderator)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleParticipant,
}, nil)
_, err := uc.CreateUser(ctx, "username", "password", models.RoleModerator)
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
t.Run("invalid user create 5 (no permission, moderator < admin)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleModerator,
}, nil)
_, err := uc.CreateUser(ctx, "username", "password", models.RoleAdmin)
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
t.Run("invalid user create 6 (bad input, bad username)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).Times(2)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleModerator,
}, nil)
caller.EXPECT().CreateUser(ctx,
"test",
"password",
models.RoleParticipant,
).Return(int32(0), pkg.ErrBadInput)
_, err := uc.CreateUser(ctx, "test", "password", models.RoleParticipant)
require.Error(t, err)
require.ErrorIs(t, err, pkg.ErrBadInput)
})
}
func TestUseCase_ReadUserById(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
pgRepository := mock_users.NewMockPgRepository(ctrl)
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
caller := mock_users.NewMockCaller(ctrl)
uc := NewUseCase(
pgRepository,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid user read", func(t *testing.T) {
userId := int32(1)
ctx := context.Background()
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{Id: userId}, nil)
user, err := uc.ReadUserById(ctx, userId)
require.NoError(t, err)
require.Equal(t, userId, user.Id)
})
t.Run("invalid user read 1 (not found)", func(t *testing.T) {
userId := int32(0)
ctx := context.Background()
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserById(ctx, userId).Return(nil, pkg.ErrNotFound)
_, err := uc.ReadUserById(ctx, userId)
require.Error(t, err)
require.ErrorIs(t, err, pkg.ErrNotFound)
})
}
func TestUseCase_ReadUserByUsername(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
pgRepository := mock_users.NewMockPgRepository(ctrl)
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
caller := mock_users.NewMockCaller(ctrl)
uc := NewUseCase(
pgRepository,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid user read", func(t *testing.T) {
username := "username"
ctx := context.Background()
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserByUsername(ctx, username).Return(&models.User{Username: username}, nil)
user, err := uc.ReadUserByUsername(ctx, username)
require.NoError(t, err)
require.Equal(t, username, user.Username)
})
t.Run("invalid user read 1 (not found)", func(t *testing.T) {
username := "username"
ctx := context.Background()
pgRepository.EXPECT().C().Return(caller)
caller.EXPECT().ReadUserByUsername(ctx, username).Return(nil, pkg.ErrNotFound)
_, err := uc.ReadUserByUsername(ctx, username)
require.Error(t, err)
require.ErrorIs(t, err, pkg.ErrNotFound)
})
}
func TestUseCase_UpdateUser(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
pgRepository := mock_users.NewMockPgRepository(ctrl)
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
caller := mock_users.NewMockCaller(ctrl)
txCaller := mock_users.NewMockTxCaller(ctrl)
uc := NewUseCase(
pgRepository,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid user update", func(t *testing.T) {
userId := int32(1)
userId2 := int32(2)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).AnyTimes()
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleAdmin,
}, nil)
caller.EXPECT().ReadUserById(ctx, userId2).Return(&models.User{
Id: userId2,
Role: models.RoleModerator,
}, nil)
pgRepository.EXPECT().BeginTx(ctx).Return(txCaller, nil)
txCaller.EXPECT().UpdateUser(ctx,
userId2,
StringP("newusername"),
RoleP(models.RoleParticipant),
).Return(nil)
vkRepository.EXPECT().DeleteAllSessions(ctx, userId2).Return(nil)
txCaller.EXPECT().Commit().Return(nil)
err := uc.UpdateUser(ctx, userId2, StringP("newusername"), RoleP(models.RoleParticipant))
require.NoError(t, err)
})
t.Run("invalid user update 1 (no user id in context)", func(t *testing.T) {
pgRepository.EXPECT().C().Return(caller).AnyTimes()
err := uc.UpdateUser(context.Background(), 0, StringP("newusername"), RoleP(models.RoleParticipant))
require.Error(t, err)
require.ErrorIs(t, err, pkg.ErrUnauthenticated)
})
t.Run("invalid user update 2 (cant update role of myself)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).AnyTimes()
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleAdmin,
}, nil).Times(2)
err := uc.UpdateUser(ctx, userId, StringP("newusername"), RoleP(models.RoleParticipant))
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
t.Run("invalid user update 3 (cant set role >= my role)", func(t *testing.T) {
userId := int32(1)
userId2 := int32(2)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).AnyTimes()
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleModerator,
}, nil)
caller.EXPECT().ReadUserById(ctx, userId2).Return(&models.User{
Id: userId2,
Role: models.RoleParticipant,
}, nil)
err := uc.UpdateUser(ctx, userId2, StringP("newusername"), RoleP(models.RoleModerator))
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
t.Run("invalid user update 4 (cant edit user with >= role than mine)", func(t *testing.T) {
userId := int32(1)
userId2 := int32(2)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).AnyTimes()
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleModerator,
}, nil)
caller.EXPECT().ReadUserById(ctx, userId2).Return(&models.User{
Id: userId2,
Role: models.RoleModerator,
}, nil)
err := uc.UpdateUser(ctx, userId2, StringP("newusername"), RoleP(models.RoleParticipant))
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
}
func TestUseCase_DeleteUser(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
pgRepository := mock_users.NewMockPgRepository(ctrl)
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
caller := mock_users.NewMockCaller(ctrl)
txCaller := mock_users.NewMockTxCaller(ctrl)
uc := NewUseCase(
pgRepository,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid user delete", func(t *testing.T) {
userId := int32(1)
userId2 := int32(2)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).AnyTimes()
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleAdmin,
}, nil)
pgRepository.EXPECT().BeginTx(ctx).Return(txCaller, nil)
vkRepository.EXPECT().DeleteAllSessions(ctx, userId2).Return(nil)
txCaller.EXPECT().DeleteUser(ctx, userId2).Return(nil)
txCaller.EXPECT().Commit().Return(nil)
err := uc.DeleteUser(ctx, userId2)
require.NoError(t, err)
})
t.Run("invalid delete (cant delete myself)", func(t *testing.T) {
userId := int32(1)
ctx := context.WithValue(context.Background(), "userId", userId)
pgRepository.EXPECT().C().Return(caller).AnyTimes()
caller.EXPECT().ReadUserById(ctx, userId).Return(&models.User{
Id: userId,
Role: models.RoleAdmin,
}, nil)
err := uc.DeleteUser(ctx, userId)
require.Error(t, err)
require.ErrorIs(t, err, pkg.NoPermission)
})
}
func TestUseCase_CreateSession(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
uc := NewUseCase(
nil,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid session creation", func(t *testing.T) {
ctx := context.Background()
sid := uuid.NewString()
vkRepository.EXPECT().CreateSession(ctx, int32(1), models.RoleAdmin).Return(sid, nil)
sessionId, err := uc.CreateSession(ctx, int32(1), models.RoleAdmin)
require.NoError(t, err)
require.Equal(t, sessionId, sid)
})
}
func TestUseCase_ReadSession(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
uc := NewUseCase(
nil,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid session read", func(t *testing.T) {
ctx := context.Background()
sid := uuid.NewString()
vkRepository.EXPECT().ReadSession(ctx, sid).Return(&models.Session{
UserId: 1,
Id: sid,
Role: models.RoleAdmin,
}, nil)
session, err := uc.ReadSession(ctx, sid)
require.NoError(t, err)
require.Equal(t, session.Id, sid)
require.Equal(t, session.UserId, int32(1))
require.Equal(t, session.Role, models.RoleAdmin)
})
}
func TestUseCase_UpdateSession(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
uc := NewUseCase(
nil,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid session update", func(t *testing.T) {
ctx := context.Background()
sid := uuid.NewString()
vkRepository.EXPECT().UpdateSession(ctx, sid).Return(nil)
err := uc.UpdateSession(ctx, sid)
require.NoError(t, err)
})
}
func TestUseCase_DeleteSession(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
uc := NewUseCase(
nil,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid session delete", func(t *testing.T) {
ctx := context.Background()
sid := uuid.NewString()
vkRepository.EXPECT().DeleteSession(ctx, sid).Return(nil)
err := uc.DeleteSession(ctx, sid)
require.NoError(t, err)
})
}
func TestUseCase_DeleteAllSessions(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
uc := NewUseCase(
nil,
vkRepository,
config.Config{
JWTSecret: "abc",
},
)
t.Run("valid session delete", func(t *testing.T) {
ctx := context.Background()
userId := int32(1)
vkRepository.EXPECT().DeleteAllSessions(ctx, userId).Return(nil)
err := uc.DeleteAllSessions(ctx, userId)
require.NoError(t, err)
})
}
func TestUseCase_Verify(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
vkRepository := mock_users.NewMockValkeyRepository(ctrl)
cfg := config.Config{JWTSecret: "abc"}
uc := NewUseCase(
nil,
vkRepository,
cfg,
)
t.Run("valid verification", func(t *testing.T) {
ctx := context.Background()
rsess := &models.Session{
Id: uuid.NewString(),
UserId: 1,
Role: models.RoleAdmin,
}
vkRepository.EXPECT().ReadSession(ctx, rsess.Id).Return(rsess, nil)
session, err := uc.Verify(ctx, rsess.Id)
require.NoError(t, err)
token, err := jwt.ParseWithClaims(session, &Token{}, func(token *jwt.Token) (interface{}, error) {
return []byte(cfg.JWTSecret), nil
})
claims, ok := token.Claims.(*Token)
require.True(t, ok)
require.NoError(t, err)
require.Equal(t, claims.SessionId, rsess.Id)
require.Equal(t, claims.UserId, rsess.UserId)
require.Equal(t, claims.Role, rsess.Role)
})
}
func StringP(s string) *string {
return &s
}
func RoleP(r models.Role) *models.Role {
return &r
}