mirror of
https://github.com/ForFarmTeam/ForFarm.git
synced 2025-12-18 21:44:08 +01:00
240 lines
6.0 KiB
Go
240 lines
6.0 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"github.com/danielgtaylor/huma/v2"
|
|
"github.com/forfarm/backend/internal/utilities"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"log/slog"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/forfarm/backend/internal/domain"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
)
|
|
|
|
type MockUserRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type EmailPasswordInput struct {
|
|
Email string `json:"email" example:"Email address of the user"`
|
|
Password string `json:"password" example:"Password of the user"`
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByID(ctx context.Context, id int64) (domain.User, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByUUID(ctx context.Context, uuid string) (domain.User, error) {
|
|
args := m.Called(ctx, uuid)
|
|
return args.Get(0).(domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByUsername(ctx context.Context, username string) (domain.User, error) {
|
|
args := m.Called(ctx, username)
|
|
return args.Get(0).(domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByEmail(ctx context.Context, email string) (domain.User, error) {
|
|
args := m.Called(ctx, email)
|
|
return args.Get(0).(domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) CreateOrUpdate(ctx context.Context, u *domain.User) error {
|
|
args := m.Called(ctx, u)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) Delete(ctx context.Context, id int64) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func TestRegisterHandler(t *testing.T) {
|
|
var tests = []struct {
|
|
name string
|
|
input RegisterInput
|
|
mockSetup func(*MockUserRepository)
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "successful registration",
|
|
input: RegisterInput{
|
|
Body: EmailPasswordInput{
|
|
Email: "test@example.com",
|
|
Password: "ValidPass123!",
|
|
},
|
|
},
|
|
mockSetup: func(m *MockUserRepository) {
|
|
m.On("GetByEmail", mock.Anything, "test@example.com").Return(domain.User{}, domain.ErrNotFound)
|
|
m.On("CreateOrUpdate", mock.Anything, mock.AnythingOfType("*domain.User")).Return(nil)
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
|
|
{
|
|
name: "existing email",
|
|
input: RegisterInput{
|
|
Body: struct {
|
|
Email string `json:"email" example:"Email address of the user"`
|
|
Password string `json:"password" example:"Password of the user"`
|
|
}(struct {
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
}{
|
|
Email: "existing@example.com",
|
|
Password: "ValidPass123!",
|
|
}),
|
|
},
|
|
mockSetup: func(m *MockUserRepository) {
|
|
m.On("GetByEmail", mock.Anything, "existing@example.com").Return(domain.User{
|
|
Email: "existing@example.com",
|
|
}, nil)
|
|
},
|
|
expectedError: huma.Error409Conflict("User with this email already exists"),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
mockRepo := &MockUserRepository{}
|
|
if tt.mockSetup != nil {
|
|
tt.mockSetup(mockRepo)
|
|
}
|
|
|
|
api := &api{
|
|
userRepo: mockRepo,
|
|
logger: nil,
|
|
}
|
|
|
|
_, err := api.registerHandler(context.Background(), &tt.input)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tt.expectedError.Error())
|
|
}
|
|
|
|
mockRepo.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoginHandler(t *testing.T) {
|
|
correctPassword := "ValidPass123!"
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(correctPassword), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
t.Fatalf("Failed to generate bcrypt hash: %v", err)
|
|
}
|
|
|
|
userUUID := uuid.New().String()
|
|
testUser := domain.User{
|
|
UUID: userUUID,
|
|
Email: "test@example.com",
|
|
Password: string(hashedPassword),
|
|
IsActive: true,
|
|
}
|
|
|
|
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: slog.LevelError,
|
|
}))
|
|
|
|
tests := []struct {
|
|
name string
|
|
input LoginInput
|
|
mockSetup func(*MockUserRepository)
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "successful login",
|
|
input: LoginInput{
|
|
Body: EmailPasswordInput{
|
|
Email: "test@example.com",
|
|
Password: correctPassword,
|
|
},
|
|
},
|
|
mockSetup: func(m *MockUserRepository) {
|
|
m.On("GetByEmail", mock.Anything, "test@example.com").Return(testUser, nil)
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "invalid credentials",
|
|
input: LoginInput{
|
|
Body: EmailPasswordInput{
|
|
Email: "test@example.com",
|
|
Password: "wrongpassword",
|
|
},
|
|
},
|
|
mockSetup: func(m *MockUserRepository) {
|
|
m.On("GetByEmail", mock.Anything, "test@example.com").Return(testUser, nil)
|
|
},
|
|
expectedError: huma.Error401Unauthorized("Invalid email or password"),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
mockRepo := &MockUserRepository{}
|
|
if tt.mockSetup != nil {
|
|
tt.mockSetup(mockRepo)
|
|
}
|
|
|
|
api := &api{
|
|
userRepo: mockRepo,
|
|
logger: logger,
|
|
}
|
|
|
|
_, err := api.loginHandler(context.Background(), &tt.input)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tt.expectedError.Error())
|
|
}
|
|
|
|
mockRepo.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoginHandler_TokenGeneration(t *testing.T) {
|
|
userUUID := uuid.New().String()
|
|
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("ValidPass123!"), bcrypt.DefaultCost)
|
|
testUser := domain.User{
|
|
UUID: userUUID,
|
|
Email: "test@example.com",
|
|
Password: string(hashedPassword),
|
|
IsActive: true,
|
|
}
|
|
|
|
mockRepo := &MockUserRepository{}
|
|
mockRepo.On("GetByEmail", mock.Anything, "test@example.com").Return(testUser, nil)
|
|
|
|
api := &api{
|
|
userRepo: mockRepo,
|
|
logger: nil,
|
|
}
|
|
|
|
input := &LoginInput{
|
|
Body: EmailPasswordInput{
|
|
Email: "test@example.com",
|
|
Password: "ValidPass123!",
|
|
},
|
|
}
|
|
|
|
output, err := api.loginHandler(context.Background(), input)
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, output.Body.Token)
|
|
|
|
err = utilities.VerifyJwtToken(output.Body.Token)
|
|
assert.NoError(t, err)
|
|
|
|
extractedUUID, err := utilities.ExtractUUIDFromToken(output.Body.Token)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, userUUID, extractedUUID)
|
|
}
|