Files
SEEN/backend/internal/services/auth/service_test.go
T
2026-04-10 12:06:24 +02:00

166 lines
4.2 KiB
Go

package auth
import (
"context"
"errors"
"testing"
"time"
"github.com/google/uuid"
"github.com/tdvorak/seen/backend/internal/config"
"github.com/tdvorak/seen/backend/internal/domain"
"github.com/tdvorak/seen/backend/internal/repositories/postgres"
"go.uber.org/zap"
)
type inMemoryRepo struct {
usersByEmail map[string]domain.User
sessions map[string]domain.Session
}
func newInMemoryRepo() *inMemoryRepo {
return &inMemoryRepo{
usersByEmail: make(map[string]domain.User),
sessions: make(map[string]domain.Session),
}
}
func (r *inMemoryRepo) CreateUser(_ context.Context, user domain.User) error {
if _, exists := r.usersByEmail[user.Email]; exists {
return postgres.ErrUserAlreadyExists
}
r.usersByEmail[user.Email] = user
return nil
}
func (r *inMemoryRepo) FindUserByEmail(_ context.Context, email string) (*domain.User, error) {
user, exists := r.usersByEmail[email]
if !exists {
return nil, nil
}
copy := user
return &copy, nil
}
func (r *inMemoryRepo) FindUserByID(_ context.Context, userID uuid.UUID) (*domain.User, error) {
for _, user := range r.usersByEmail {
if user.ID == userID {
copy := user
return &copy, nil
}
}
return nil, nil
}
func (r *inMemoryRepo) CreateSession(_ context.Context, session domain.Session) error {
r.sessions[session.RefreshToken] = session
return nil
}
func (r *inMemoryRepo) FindSessionByRefreshToken(_ context.Context, refreshToken string) (*domain.Session, error) {
session, exists := r.sessions[refreshToken]
if !exists {
return nil, nil
}
copy := session
return &copy, nil
}
func (r *inMemoryRepo) RevokeSession(_ context.Context, sessionID uuid.UUID) error {
now := time.Now().UTC()
for token, session := range r.sessions {
if session.ID == sessionID {
session.RevokedAt = &now
r.sessions[token] = session
return nil
}
}
return errors.New("session not found")
}
func TestRegisterValidation(t *testing.T) {
svc := NewService(newInMemoryRepo(), config.AuthConfig{AccessTokenTTLMinutes: 10, RefreshTokenTTLHours: 1, JWTSecret: "test"}, zap.NewNop())
_, err := svc.Register(context.Background(), RegisterInput{
Email: "",
Password: "short",
})
if !errors.Is(err, ErrInvalidInput) {
t.Fatalf("expected invalid input error, got %v", err)
}
}
func TestRegisterAndLoginFlow(t *testing.T) {
repo := newInMemoryRepo()
svc := NewService(repo, config.AuthConfig{AccessTokenTTLMinutes: 10, RefreshTokenTTLHours: 1, JWTSecret: "test"}, zap.NewNop())
registered, err := svc.Register(context.Background(), RegisterInput{
Email: "user@example.com",
Password: "password123",
DisplayName: "Seen User",
})
if err != nil {
t.Fatalf("register failed: %v", err)
}
if registered.AccessToken == "" || registered.RefreshToken == "" {
t.Fatalf("expected issued tokens")
}
loggedIn, err := svc.Login(context.Background(), LoginInput{
Email: "user@example.com",
Password: "password123",
})
if err != nil {
t.Fatalf("login failed: %v", err)
}
if loggedIn.AccessToken == "" {
t.Fatalf("expected login access token")
}
}
func TestLoginWrongPassword(t *testing.T) {
repo := newInMemoryRepo()
svc := NewService(repo, config.AuthConfig{AccessTokenTTLMinutes: 10, RefreshTokenTTLHours: 1, JWTSecret: "test"}, zap.NewNop())
_, err := svc.Register(context.Background(), RegisterInput{
Email: "user@example.com",
Password: "password123",
})
if err != nil {
t.Fatalf("register failed: %v", err)
}
_, err = svc.Login(context.Background(), LoginInput{
Email: "user@example.com",
Password: "wrongpass",
})
if !errors.Is(err, ErrInvalidCredentials) {
t.Fatalf("expected invalid credentials error, got %v", err)
}
}
func TestUserFromAccessToken(t *testing.T) {
repo := newInMemoryRepo()
svc := NewService(repo, config.AuthConfig{AccessTokenTTLMinutes: 10, RefreshTokenTTLHours: 1, JWTSecret: "test"}, zap.NewNop())
authResult, err := svc.Register(context.Background(), RegisterInput{
Email: "user@example.com",
Password: "password123",
})
if err != nil {
t.Fatalf("register failed: %v", err)
}
user, err := svc.UserFromAccessToken(context.Background(), authResult.AccessToken)
if err != nil {
t.Fatalf("user from access token failed: %v", err)
}
if user.Email != "user@example.com" {
t.Fatalf("expected user email, got %s", user.Email)
}
}