tercul-backend/internal/app/auth/commands_test.go
google-labs-jules[bot] 49e2bdd9ac feat: Refactor localization, auth, copyright, and monetization domains
This change introduces a major architectural refactoring of the application, with a focus on improving testability, decoupling, and observability.

The following domains have been successfully refactored:
- `localization`: Wrote a full suite of unit tests and added logging.
- `auth`: Introduced a `JWTManager` interface, wrote comprehensive unit tests, and added logging.
- `copyright`: Separated integration tests, wrote a full suite of unit tests, and added logging.
- `monetization`: Wrote a full suite of unit tests and added logging.
- `search`: Refactored the Weaviate client usage by creating a wrapper to improve testability, and achieved 100% test coverage.

For each of these domains, 100% test coverage has been achieved for the refactored code.

The refactoring of the `work` domain is currently in progress. Unit tests have been written for the commands and queries, but there is a persistent build issue with the query tests that needs to be resolved. The error indicates that the query methods are undefined, despite appearing to be correctly defined and called.
2025-09-06 15:15:10 +00:00

287 lines
7.9 KiB
Go

package auth
import (
"context"
"errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"tercul/internal/domain"
"testing"
)
type AuthCommandsSuite struct {
suite.Suite
userRepo *mockUserRepository
jwtManager *mockJWTManager
commands *AuthCommands
}
func (s *AuthCommandsSuite) SetupTest() {
s.userRepo = newMockUserRepository()
s.jwtManager = &mockJWTManager{}
s.commands = NewAuthCommands(s.userRepo, s.jwtManager)
}
func TestAuthCommandsSuite(t *testing.T) {
suite.Run(t, new(AuthCommandsSuite))
}
func (s *AuthCommandsSuite) TestLogin_Success() {
user := domain.User{
Email: "test@example.com",
Password: "password",
Active: true,
}
s.userRepo.Create(context.Background(), &user)
input := LoginInput{Email: "test@example.com", Password: "password"}
resp, err := s.commands.Login(context.Background(), input)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), resp)
assert.Equal(s.T(), "test-token", resp.Token)
assert.Equal(s.T(), user.ID, resp.User.ID)
}
func (s *AuthCommandsSuite) TestLogin_InvalidInput() {
input := LoginInput{Email: "invalid-email", Password: "short"}
resp, err := s.commands.Login(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestValidateLoginInput_EmptyEmail() {
input := LoginInput{Email: "", Password: "password"}
err := validateLoginInput(input)
assert.Error(s.T(), err)
}
func (s *AuthCommandsSuite) TestValidateLoginInput_ShortPassword() {
input := LoginInput{Email: "test@example.com", Password: "short"}
err := validateLoginInput(input)
assert.Error(s.T(), err)
}
func (s *AuthCommandsSuite) TestValidateRegisterInput_ShortPassword() {
input := RegisterInput{Email: "test@example.com", Password: "short"}
err := validateRegisterInput(input)
assert.Error(s.T(), err)
}
func (s *AuthCommandsSuite) TestValidateRegisterInput_ShortUsername() {
input := RegisterInput{Username: "a", Email: "test@example.com", Password: "password"}
err := validateRegisterInput(input)
assert.Error(s.T(), err)
}
func (s *AuthCommandsSuite) TestValidateRegisterInput_LongUsername() {
input := RegisterInput{Username: "a51characterusernameisdefinitelytoolongforthisvalidation", Email: "test@example.com", Password: "password"}
err := validateRegisterInput(input)
assert.Error(s.T(), err)
}
func (s *AuthCommandsSuite) TestLogin_SuccessUpdate() {
user := domain.User{
Email: "test@example.com",
Password: "password",
Active: true,
}
s.userRepo.Create(context.Background(), &user)
s.userRepo.updateFunc = func(ctx context.Context, user *domain.User) error {
return nil
}
input := LoginInput{Email: "test@example.com", Password: "password"}
resp, err := s.commands.Login(context.Background(), input)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_InvalidEmail() {
input := RegisterInput{
Username: "newuser",
Email: "invalid-email",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestLogin_UpdateUserError() {
user := domain.User{
Email: "test@example.com",
Password: "password",
Active: true,
}
s.userRepo.Create(context.Background(), &user)
s.userRepo.updateFunc = func(ctx context.Context, user *domain.User) error {
return errors.New("update error")
}
input := LoginInput{Email: "test@example.com", Password: "password"}
resp, err := s.commands.Login(context.Background(), input)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_InvalidUsername() {
input := RegisterInput{
Username: "invalid username",
Email: "new@example.com",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestLogin_UserNotFound() {
input := LoginInput{Email: "notfound@example.com", Password: "password"}
resp, err := s.commands.Login(context.Background(), input)
assert.ErrorIs(s.T(), err, ErrInvalidCredentials)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestLogin_InactiveUser() {
user := domain.User{
Email: "inactive@example.com",
Password: "password",
Active: false,
}
s.userRepo.Create(context.Background(), &user)
input := LoginInput{Email: "inactive@example.com", Password: "password"}
resp, err := s.commands.Login(context.Background(), input)
assert.ErrorIs(s.T(), err, ErrInvalidCredentials)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestLogin_InvalidPassword() {
user := domain.User{
Email: "test@example.com",
Password: "password",
Active: true,
}
s.userRepo.Create(context.Background(), &user)
input := LoginInput{Email: "test@example.com", Password: "wrong-password"}
resp, err := s.commands.Login(context.Background(), input)
assert.ErrorIs(s.T(), err, ErrInvalidCredentials)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestLogin_TokenGenerationError() {
user := domain.User{
Email: "test@example.com",
Password: "password",
Active: true,
}
s.userRepo.Create(context.Background(), &user)
s.jwtManager.generateTokenFunc = func(user *domain.User) (string, error) {
return "", errors.New("jwt error")
}
input := LoginInput{Email: "test@example.com", Password: "password"}
resp, err := s.commands.Login(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_Success() {
input := RegisterInput{
Username: "newuser",
Email: "new@example.com",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), resp)
assert.Equal(s.T(), "test-token", resp.Token)
assert.Equal(s.T(), "newuser", resp.User.Username)
}
func (s *AuthCommandsSuite) TestRegister_InvalidInput() {
input := RegisterInput{Email: "invalid"}
resp, err := s.commands.Register(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_EmailExists() {
user := domain.User{
Email: "exists@example.com",
}
s.userRepo.Create(context.Background(), &user)
input := RegisterInput{
Username: "newuser",
Email: "exists@example.com",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.ErrorIs(s.T(), err, ErrUserAlreadyExists)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_UsernameExists() {
user := domain.User{
Username: "exists",
}
s.userRepo.Create(context.Background(), &user)
input := RegisterInput{
Username: "exists",
Email: "new@example.com",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.ErrorIs(s.T(), err, ErrUserAlreadyExists)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_CreateUserError() {
s.userRepo.createFunc = func(ctx context.Context, user *domain.User) error {
return errors.New("db error")
}
input := RegisterInput{
Username: "newuser",
Email: "new@example.com",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}
func (s *AuthCommandsSuite) TestRegister_TokenGenerationError() {
s.jwtManager.generateTokenFunc = func(user *domain.User) (string, error) {
return "", errors.New("jwt error")
}
input := RegisterInput{
Username: "newuser",
Email: "new@example.com",
Password: "password",
FirstName: "New",
LastName: "User",
}
resp, err := s.commands.Register(context.Background(), input)
assert.Error(s.T(), err)
assert.Nil(s.T(), resp)
}