mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 04:01:34 +00:00
Some checks failed
- Updated database models and repositories to replace uint IDs with UUIDs. - Modified test fixtures to generate and use UUIDs for authors, translations, users, and works. - Adjusted mock implementations to align with the new UUID structure. - Ensured all relevant functions and methods are updated to handle UUIDs correctly. - Added necessary imports for UUID handling in various files.
638 lines
20 KiB
Go
638 lines
20 KiB
Go
package graphql
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"tercul/internal/adapters/graphql/model"
|
|
"tercul/internal/app"
|
|
"tercul/internal/app/authz"
|
|
"tercul/internal/app/user"
|
|
"tercul/internal/domain"
|
|
platform_auth "tercul/internal/platform/auth"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/suite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// mockUserRepositoryForUserResolver is a mock for the user repository.
|
|
type mockUserRepositoryForUserResolver struct{ mock.Mock }
|
|
|
|
// Implement domain.UserRepository
|
|
func (m *mockUserRepositoryForUserResolver) GetByID(ctx context.Context, id uuid.UUID) (*domain.User, error) {
|
|
args := m.Called(ctx, id)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) FindByUsername(ctx context.Context, username string) (*domain.User, error) {
|
|
args := m.Called(ctx, username)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
|
args := m.Called(ctx, email)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) ListByRole(ctx context.Context, role domain.UserRole) ([]domain.User, error) {
|
|
args := m.Called(ctx, role)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) Create(ctx context.Context, entity *domain.User) error {
|
|
return m.Called(ctx, entity).Error(0)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.User) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) Update(ctx context.Context, entity *domain.User) error {
|
|
return m.Called(ctx, entity).Error(0)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.User) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) Delete(ctx context.Context, id uint) error {
|
|
return m.Called(ctx, id).Error(0)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.User], error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) ListAll(ctx context.Context) ([]domain.User, error) {
|
|
args := m.Called(ctx)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) Count(ctx context.Context) (int64, error) { return 0, nil }
|
|
func (m *mockUserRepositoryForUserResolver) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
return 0, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.User, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) Exists(ctx context.Context, id uint) (bool, error) {
|
|
return false, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserRepositoryForUserResolver) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return nil
|
|
}
|
|
|
|
// mockUserProfileRepository is a mock for the user profile repository.
|
|
type mockUserProfileRepository struct{ mock.Mock }
|
|
|
|
// Implement domain.UserProfileRepository
|
|
func (m *mockUserProfileRepository) GetByUserID(ctx context.Context, userID uuid.UUID) (*domain.UserProfile, error) {
|
|
args := m.Called(ctx, userID)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*domain.UserProfile), args.Error(1)
|
|
}
|
|
|
|
// Implement BaseRepository methods for UserProfile
|
|
func (m *mockUserProfileRepository) Create(ctx context.Context, entity *domain.UserProfile) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserProfileRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.UserProfile) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserProfileRepository) GetByID(ctx context.Context, id uuid.UUID) (*domain.UserProfile, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.UserProfile, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) Update(ctx context.Context, entity *domain.UserProfile) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserProfileRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.UserProfile) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserProfileRepository) Delete(ctx context.Context, id uint) error { return nil }
|
|
func (m *mockUserProfileRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
return nil
|
|
}
|
|
func (m *mockUserProfileRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.UserProfile], error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.UserProfile, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) ListAll(ctx context.Context) ([]domain.UserProfile, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) Count(ctx context.Context) (int64, error) { return 0, nil }
|
|
func (m *mockUserProfileRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
return 0, nil
|
|
}
|
|
func (m *mockUserProfileRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.UserProfile, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.UserProfile, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockUserProfileRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
return false, nil
|
|
}
|
|
func (m *mockUserProfileRepository) BeginTx(ctx context.Context) (*gorm.DB, error) { return nil, nil }
|
|
func (m *mockUserProfileRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return nil
|
|
}
|
|
|
|
// UserResolversUnitSuite is a unit test suite for the user resolvers.
|
|
type UserResolversUnitSuite struct {
|
|
suite.Suite
|
|
resolver *Resolver
|
|
mockUserRepo *mockUserRepositoryForUserResolver
|
|
mockUserProfileRepo *mockUserProfileRepository
|
|
}
|
|
|
|
// SetupTest sets up the test suite
|
|
func (s *UserResolversUnitSuite) SetupTest() {
|
|
s.mockUserRepo = new(mockUserRepositoryForUserResolver)
|
|
s.mockUserProfileRepo = new(mockUserProfileRepository)
|
|
|
|
// The authz service dependencies are not needed for the user commands being tested.
|
|
authzSvc := authz.NewService(nil, nil, s.mockUserRepo, nil)
|
|
|
|
userCommands := user.NewUserCommands(s.mockUserRepo, authzSvc)
|
|
userQueries := user.NewUserQueries(s.mockUserRepo, s.mockUserProfileRepo)
|
|
|
|
userService := &user.Service{
|
|
Commands: userCommands,
|
|
Queries: userQueries,
|
|
}
|
|
|
|
s.resolver = &Resolver{
|
|
App: &app.Application{
|
|
User: userService,
|
|
},
|
|
}
|
|
}
|
|
|
|
// TestUserResolversUnitSuite runs the test suite
|
|
func TestUserResolversUnitSuite(t *testing.T) {
|
|
suite.Run(t, new(UserResolversUnitSuite))
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUserQuery() {
|
|
s.Run("Success", func() {
|
|
s.SetupTest()
|
|
userID := uint(1)
|
|
userIDStr := "1"
|
|
ctx := context.Background()
|
|
|
|
expectedUser := &domain.User{
|
|
Username: "testuser",
|
|
Email: "test@test.com",
|
|
Role: domain.UserRoleReader,
|
|
}
|
|
expectedUser.ID = userID
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, userID).Return(expectedUser, nil).Once()
|
|
|
|
gqlUser, err := s.resolver.Query().User(ctx, userIDStr)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(gqlUser)
|
|
s.Equal(userIDStr, gqlUser.ID)
|
|
s.Equal(expectedUser.Username, gqlUser.Username)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Not Found", func() {
|
|
s.SetupTest()
|
|
userID := uint(99)
|
|
userIDStr := "99"
|
|
ctx := context.Background()
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, userID).Return(nil, domain.ErrEntityNotFound).Once()
|
|
|
|
gqlUser, err := s.resolver.Query().User(ctx, userIDStr)
|
|
|
|
s.Require().Error(err) // The resolver should propagate the error
|
|
s.Require().Nil(gqlUser)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Invalid ID", func() {
|
|
s.SetupTest()
|
|
ctx := context.Background()
|
|
_, err := s.resolver.Query().User(ctx, "invalid")
|
|
s.Require().Error(err)
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUserProfileQuery() {
|
|
s.Run("Success", func() {
|
|
s.SetupTest()
|
|
userID := uint(1)
|
|
userIDStr := "1"
|
|
ctx := context.Background()
|
|
|
|
expectedProfile := &domain.UserProfile{
|
|
UserID: userID,
|
|
PhoneNumber: "12345",
|
|
}
|
|
expectedProfile.ID = 1
|
|
|
|
expectedUser := &domain.User{
|
|
Username: "testuser",
|
|
}
|
|
expectedUser.ID = userID
|
|
|
|
s.mockUserProfileRepo.On("GetByUserID", mock.Anything, userID).Return(expectedProfile, nil).Once()
|
|
s.mockUserRepo.On("GetByID", mock.Anything, userID).Return(expectedUser, nil).Once()
|
|
|
|
gqlProfile, err := s.resolver.Query().UserProfile(ctx, userIDStr)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(gqlProfile)
|
|
s.Equal(userIDStr, gqlProfile.UserID)
|
|
s.Equal(&expectedProfile.PhoneNumber, gqlProfile.PhoneNumber)
|
|
s.mockUserProfileRepo.AssertExpectations(s.T())
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Profile Not Found", func() {
|
|
s.SetupTest()
|
|
userID := uint(99)
|
|
userIDStr := "99"
|
|
ctx := context.Background()
|
|
|
|
s.mockUserProfileRepo.On("GetByUserID", mock.Anything, userID).Return(nil, domain.ErrEntityNotFound).Once()
|
|
|
|
gqlProfile, err := s.resolver.Query().UserProfile(ctx, userIDStr)
|
|
|
|
s.Require().Error(err)
|
|
s.Require().Nil(gqlProfile)
|
|
s.mockUserProfileRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("User Not Found for profile", func() {
|
|
s.SetupTest()
|
|
userID := uint(1)
|
|
userIDStr := "1"
|
|
ctx := context.Background()
|
|
|
|
expectedProfile := &domain.UserProfile{
|
|
UserID: userID,
|
|
}
|
|
expectedProfile.ID = 1
|
|
|
|
s.mockUserProfileRepo.On("GetByUserID", mock.Anything, userID).Return(expectedProfile, nil).Once()
|
|
s.mockUserRepo.On("GetByID", mock.Anything, userID).Return(nil, domain.ErrEntityNotFound).Once()
|
|
|
|
_, err := s.resolver.Query().UserProfile(ctx, userIDStr)
|
|
|
|
s.Require().Error(err)
|
|
s.mockUserProfileRepo.AssertExpectations(s.T())
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUpdateProfileMutation() {
|
|
s.Run("Success", func() {
|
|
s.SetupTest()
|
|
actorID := uint(1)
|
|
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleReader),
|
|
})
|
|
|
|
displayName := "New Name"
|
|
input := model.UserInput{DisplayName: &displayName}
|
|
|
|
originalUser := &domain.User{DisplayName: "Old Name"}
|
|
originalUser.ID = actorID
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, actorID).Return(originalUser, nil).Once()
|
|
s.mockUserRepo.On("Update", mock.Anything, mock.MatchedBy(func(u *domain.User) bool {
|
|
return u.ID == actorID && u.DisplayName == displayName
|
|
})).Return(nil).Once()
|
|
|
|
updatedUser, err := s.resolver.Mutation().UpdateProfile(ctx, input)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(updatedUser)
|
|
s.Equal(displayName, *updatedUser.DisplayName)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Unauthorized", func() {
|
|
s.SetupTest()
|
|
ctx := context.Background() // no user
|
|
displayName := "New Name"
|
|
input := model.UserInput{DisplayName: &displayName}
|
|
|
|
_, err := s.resolver.Mutation().UpdateProfile(ctx, input)
|
|
s.Require().Error(err)
|
|
s.ErrorIs(err, domain.ErrUnauthorized)
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUpdateUserMutation() {
|
|
s.Run("Success as self", func() {
|
|
s.SetupTest()
|
|
actorID := uint(1)
|
|
targetID := uint(1)
|
|
targetIDStr := "1"
|
|
username := "new_username"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleReader),
|
|
})
|
|
input := model.UserInput{Username: &username}
|
|
|
|
originalUser := &domain.User{Username: "old_username"}
|
|
originalUser.ID = targetID
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, targetID).Return(originalUser, nil).Once()
|
|
s.mockUserRepo.On("Update", mock.Anything, mock.MatchedBy(func(u *domain.User) bool {
|
|
return u.ID == targetID && u.Username == username
|
|
})).Return(nil).Once()
|
|
|
|
updatedUser, err := s.resolver.Mutation().UpdateUser(ctx, targetIDStr, input)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(updatedUser)
|
|
s.Equal(username, updatedUser.Username)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Success as admin", func() {
|
|
s.SetupTest()
|
|
actorID := uint(99) // Admin
|
|
targetID := uint(1)
|
|
targetIDStr := "1"
|
|
username := "new_username"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleAdmin),
|
|
})
|
|
input := model.UserInput{Username: &username}
|
|
|
|
originalUser := &domain.User{Username: "old_username"}
|
|
originalUser.ID = targetID
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, targetID).Return(originalUser, nil).Once()
|
|
s.mockUserRepo.On("Update", mock.Anything, mock.MatchedBy(func(u *domain.User) bool {
|
|
return u.ID == targetID && u.Username == username
|
|
})).Return(nil).Once()
|
|
|
|
updatedUser, err := s.resolver.Mutation().UpdateUser(ctx, targetIDStr, input)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(updatedUser)
|
|
s.Equal(username, updatedUser.Username)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Forbidden", func() {
|
|
s.SetupTest()
|
|
actorID := uint(2)
|
|
targetIDStr := "1"
|
|
username := "new_username"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleReader),
|
|
})
|
|
input := model.UserInput{Username: &username}
|
|
|
|
_, err := s.resolver.Mutation().UpdateUser(ctx, targetIDStr, input)
|
|
|
|
s.Require().Error(err)
|
|
s.ErrorIs(err, domain.ErrForbidden)
|
|
s.mockUserRepo.AssertNotCalled(s.T(), "GetByID")
|
|
s.mockUserRepo.AssertNotCalled(s.T(), "Update")
|
|
})
|
|
|
|
s.Run("User not found", func() {
|
|
s.SetupTest()
|
|
actorID := uint(1)
|
|
targetID := uint(1)
|
|
targetIDStr := "1"
|
|
username := "new_username"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleReader),
|
|
})
|
|
input := model.UserInput{Username: &username}
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, targetID).Return(nil, domain.ErrEntityNotFound).Once()
|
|
|
|
_, err := s.resolver.Mutation().UpdateUser(ctx, targetIDStr, input)
|
|
|
|
s.Require().Error(err)
|
|
s.ErrorIs(err, domain.ErrEntityNotFound)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
s.mockUserRepo.AssertNotCalled(s.T(), "Update")
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUsersQuery() {
|
|
s.Run("Success without role", func() {
|
|
s.SetupTest()
|
|
ctx := context.Background()
|
|
expectedUsers := []domain.User{
|
|
{Username: "user1"},
|
|
{Username: "user2"},
|
|
}
|
|
s.mockUserRepo.On("ListAll", mock.Anything).Return(expectedUsers, nil).Once()
|
|
|
|
users, err := s.resolver.Query().Users(ctx, nil, nil, nil)
|
|
|
|
s.Require().NoError(err)
|
|
s.Len(users, 2)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Success with role", func() {
|
|
s.SetupTest()
|
|
ctx := context.Background()
|
|
role := domain.UserRoleAdmin
|
|
modelRole := model.UserRoleAdmin
|
|
expectedUsers := []domain.User{
|
|
{Username: "admin1", Role: role},
|
|
}
|
|
s.mockUserRepo.On("ListByRole", mock.Anything, role).Return(expectedUsers, nil).Once()
|
|
|
|
users, err := s.resolver.Query().Users(ctx, nil, nil, &modelRole)
|
|
|
|
s.Require().NoError(err)
|
|
s.Len(users, 1)
|
|
s.Equal(model.UserRoleAdmin, users[0].Role)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUserByEmailQuery() {
|
|
s.Run("Success", func() {
|
|
s.SetupTest()
|
|
email := "test@test.com"
|
|
ctx := context.Background()
|
|
|
|
expectedUser := &domain.User{
|
|
Username: "testuser",
|
|
Email: email,
|
|
Role: domain.UserRoleReader,
|
|
}
|
|
expectedUser.ID = 1
|
|
|
|
s.mockUserRepo.On("FindByEmail", mock.Anything, email).Return(expectedUser, nil).Once()
|
|
|
|
gqlUser, err := s.resolver.Query().UserByEmail(ctx, email)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(gqlUser)
|
|
s.Equal(email, gqlUser.Email)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestUserByUsernameQuery() {
|
|
s.Run("Success", func() {
|
|
s.SetupTest()
|
|
username := "testuser"
|
|
ctx := context.Background()
|
|
|
|
expectedUser := &domain.User{
|
|
Username: username,
|
|
Email: "test@test.com",
|
|
Role: domain.UserRoleReader,
|
|
}
|
|
expectedUser.ID = 1
|
|
|
|
s.mockUserRepo.On("FindByUsername", mock.Anything, username).Return(expectedUser, nil).Once()
|
|
|
|
gqlUser, err := s.resolver.Query().UserByUsername(ctx, username)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(gqlUser)
|
|
s.Equal(username, gqlUser.Username)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestMeQuery() {
|
|
s.Run("Success", func() {
|
|
s.SetupTest()
|
|
userID := uint(1)
|
|
ctx := platform_auth.ContextWithUserID(context.Background(), userID)
|
|
|
|
expectedUser := &domain.User{
|
|
Username: "testuser",
|
|
Email: "test@test.com",
|
|
Role: domain.UserRoleReader,
|
|
}
|
|
expectedUser.ID = userID
|
|
|
|
s.mockUserRepo.On("GetByID", mock.Anything, userID).Return(expectedUser, nil).Once()
|
|
|
|
gqlUser, err := s.resolver.Query().Me(ctx)
|
|
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(gqlUser)
|
|
s.Equal(fmt.Sprintf("%d", userID), gqlUser.ID)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Unauthorized", func() {
|
|
s.SetupTest()
|
|
ctx := context.Background() // No user in context
|
|
_, err := s.resolver.Query().Me(ctx)
|
|
s.Require().Error(err)
|
|
s.Equal(domain.ErrUnauthorized, err)
|
|
})
|
|
}
|
|
|
|
func (s *UserResolversUnitSuite) TestDeleteUserMutation() {
|
|
s.Run("Success as self", func() {
|
|
s.SetupTest()
|
|
actorID := uint(1)
|
|
targetID := uint(1)
|
|
targetIDStr := "1"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleReader),
|
|
})
|
|
|
|
s.mockUserRepo.On("Delete", mock.Anything, targetID).Return(nil).Once()
|
|
|
|
ok, err := s.resolver.Mutation().DeleteUser(ctx, targetIDStr)
|
|
|
|
s.Require().NoError(err)
|
|
s.True(ok)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Success as admin", func() {
|
|
s.SetupTest()
|
|
actorID := uint(99) // Admin
|
|
targetID := uint(1)
|
|
targetIDStr := "1"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleAdmin),
|
|
})
|
|
|
|
s.mockUserRepo.On("Delete", mock.Anything, targetID).Return(nil).Once()
|
|
|
|
ok, err := s.resolver.Mutation().DeleteUser(ctx, targetIDStr)
|
|
|
|
s.Require().NoError(err)
|
|
s.True(ok)
|
|
s.mockUserRepo.AssertExpectations(s.T())
|
|
})
|
|
|
|
s.Run("Forbidden", func() {
|
|
s.SetupTest()
|
|
actorID := uint(2)
|
|
targetIDStr := "1"
|
|
ctx := context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{
|
|
UserID: actorID,
|
|
Role: string(domain.UserRoleReader),
|
|
})
|
|
|
|
ok, err := s.resolver.Mutation().DeleteUser(ctx, targetIDStr)
|
|
|
|
s.Require().Error(err)
|
|
s.ErrorIs(err, domain.ErrForbidden)
|
|
s.False(ok)
|
|
s.mockUserRepo.AssertNotCalled(s.T(), "Delete")
|
|
})
|
|
|
|
s.Run("Invalid ID", func() {
|
|
s.SetupTest()
|
|
ctx := context.Background()
|
|
_, err := s.resolver.Mutation().DeleteUser(ctx, "invalid")
|
|
s.Require().Error(err)
|
|
})
|
|
}
|