package service import ( "context" "testing" "time" "backupx/server/internal/model" "backupx/server/internal/security" ) type fakeUserRepository struct { users []*model.User } func (r *fakeUserRepository) Count(context.Context) (int64, error) { return int64(len(r.users)), nil } func (r *fakeUserRepository) Create(_ context.Context, user *model.User) error { user.ID = uint(len(r.users) + 1) r.users = append(r.users, user) return nil } func (r *fakeUserRepository) FindByUsername(_ context.Context, username string) (*model.User, error) { for _, user := range r.users { if user.Username == username { return user, nil } } return nil, nil } func (r *fakeUserRepository) FindByID(_ context.Context, id uint) (*model.User, error) { for _, user := range r.users { if user.ID == id { return user, nil } } return nil, nil } func (r *fakeUserRepository) Update(_ context.Context, user *model.User) error { for i, u := range r.users { if u.ID == user.ID { r.users[i] = user return nil } } return nil } type fakeSystemConfigRepository struct{} func (r *fakeSystemConfigRepository) GetByKey(context.Context, string) (*model.SystemConfig, error) { return nil, nil } func (r *fakeSystemConfigRepository) List(context.Context) ([]model.SystemConfig, error) { return nil, nil } func (r *fakeSystemConfigRepository) Upsert(context.Context, *model.SystemConfig) error { return nil } func TestAuthServiceSetupAndLogin(t *testing.T) { users := &fakeUserRepository{} service := NewAuthService( users, &fakeSystemConfigRepository{}, security.NewJWTManager("test-secret", time.Hour), security.NewLoginRateLimiter(5, time.Minute), ) setupResult, err := service.Setup(context.Background(), SetupInput{ Username: "admin", Password: "password-123", DisplayName: "Admin", }) if err != nil { t.Fatalf("Setup returned error: %v", err) } if setupResult.User.Username != "admin" { t.Fatalf("expected username admin, got %s", setupResult.User.Username) } loginResult, err := service.Login(context.Background(), LoginInput{ Username: "admin", Password: "password-123", }, "127.0.0.1") if err != nil { t.Fatalf("Login returned error: %v", err) } if loginResult.Token == "" { t.Fatalf("expected non-empty token") } } func newTestAuthService() (*AuthService, *fakeUserRepository) { users := &fakeUserRepository{} svc := NewAuthService( users, &fakeSystemConfigRepository{}, security.NewJWTManager("test-secret", time.Hour), security.NewLoginRateLimiter(5, time.Minute), ) return svc, users } func TestChangePassword(t *testing.T) { svc, _ := newTestAuthService() _, err := svc.Setup(context.Background(), SetupInput{ Username: "admin", Password: "password-123", DisplayName: "Admin", }) if err != nil { t.Fatalf("Setup: %v", err) } err = svc.ChangePassword(context.Background(), "1", ChangePasswordInput{ OldPassword: "password-123", NewPassword: "new-password-456", }) if err != nil { t.Fatalf("ChangePassword: %v", err) } // Old password should no longer work _, err = svc.Login(context.Background(), LoginInput{ Username: "admin", Password: "password-123", }, "127.0.0.1") if err == nil { t.Fatalf("expected login with old password to fail") } // New password should work _, err = svc.Login(context.Background(), LoginInput{ Username: "admin", Password: "new-password-456", }, "127.0.0.1") if err != nil { t.Fatalf("login with new password: %v", err) } } func TestChangePasswordWrongOld(t *testing.T) { svc, _ := newTestAuthService() _, err := svc.Setup(context.Background(), SetupInput{ Username: "admin", Password: "password-123", DisplayName: "Admin", }) if err != nil { t.Fatalf("Setup: %v", err) } err = svc.ChangePassword(context.Background(), "1", ChangePasswordInput{ OldPassword: "wrong-password", NewPassword: "new-password-456", }) if err == nil { t.Fatalf("expected ChangePassword with wrong old password to fail") } }