Add tests on authuser and authentication usecases
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
8c25aed1d0
commit
d6bc3b5b3f
8 changed files with 947 additions and 0 deletions
238
internal/usecase/authentication_test.go
Normal file
238
internal/usecase/authentication_test.go
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
package usecase_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase"
|
||||||
|
userUC "git.happydns.org/happyDomain/internal/usecase/user"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testUserInfo struct {
|
||||||
|
id happydns.Identifier
|
||||||
|
email string
|
||||||
|
newsletter bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u testUserInfo) GetUserId() happydns.Identifier { return u.id }
|
||||||
|
func (u testUserInfo) GetEmail() string { return u.email }
|
||||||
|
func (u testUserInfo) JoinNewsletter() bool { return u.newsletter }
|
||||||
|
|
||||||
|
func Test_CompleteAuthentication(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, nil, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{}, mem, userUsecase)
|
||||||
|
|
||||||
|
uinfo := testUserInfo{
|
||||||
|
id: happydns.Identifier([]byte("user-123")),
|
||||||
|
email: "john@example.com",
|
||||||
|
newsletter: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := authenticationUsecase.CompleteAuthentication(uinfo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if user.Email != "john@example.com" {
|
||||||
|
t.Errorf("expected email 'john@example.com', got %s", user.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the user is correctly stored in db
|
||||||
|
stored, err := mem.GetUser(happydns.Identifier([]byte("user-123")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected stored user, got error: %v", err)
|
||||||
|
}
|
||||||
|
if stored.Email != "john@example.com" {
|
||||||
|
t.Errorf("expected stored email to be john@example.com, got %s", stored.Email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNewsletterSubscription struct {
|
||||||
|
userSubscribed happydns.UserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *testNewsletterSubscription) SubscribeToNewsletter(u happydns.UserInfo) error {
|
||||||
|
ds.userSubscribed = u
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_CompleteAuthentication_WithNewsletter(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mockNewsletterSubscription := &testNewsletterSubscription{}
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, mockNewsletterSubscription, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{}, mem, userUsecase)
|
||||||
|
|
||||||
|
uinfo := testUserInfo{
|
||||||
|
id: happydns.Identifier([]byte("user-123")),
|
||||||
|
email: "john@example.com",
|
||||||
|
newsletter: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := authenticationUsecase.CompleteAuthentication(uinfo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the user has been subscribed
|
||||||
|
if mockNewsletterSubscription.userSubscribed == nil || mockNewsletterSubscription.userSubscribed.GetEmail() != uinfo.GetEmail() {
|
||||||
|
t.Errorf("user not subscribed to newsletter after first login")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the subscription state
|
||||||
|
mockNewsletterSubscription.userSubscribed = nil
|
||||||
|
|
||||||
|
// Redo the authentication, now that the user is already registered
|
||||||
|
_, err = authenticationUsecase.CompleteAuthentication(uinfo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mockNewsletterSubscription.userSubscribed != nil {
|
||||||
|
t.Errorf("user has been re-subscribed to newsletter beyond first login")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AuthenticateUserWithPassword_WrongPassword(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
|
||||||
|
authUser := &happydns.UserAuth{
|
||||||
|
Email: "a@b.c",
|
||||||
|
}
|
||||||
|
err := authUser.DefinePassword("secure")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mem.CreateAuthUser(authUser)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, nil, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{}, mem, userUsecase)
|
||||||
|
|
||||||
|
_, err = authenticationUsecase.AuthenticateUserWithPassword(happydns.LoginRequest{
|
||||||
|
Email: "a@b.c",
|
||||||
|
Password: "wrong-password",
|
||||||
|
})
|
||||||
|
if err == nil || err.Error() != `tries to login as "a@b.c", but sent an invalid password` {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AuthenticateUserWithPassword_WeakPassword(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
|
||||||
|
authUser := &happydns.UserAuth{
|
||||||
|
Email: "a@b.c",
|
||||||
|
}
|
||||||
|
err := authUser.DefinePassword("weak")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mem.CreateAuthUser(authUser)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, nil, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{}, mem, userUsecase)
|
||||||
|
|
||||||
|
_, err = authenticationUsecase.AuthenticateUserWithPassword(happydns.LoginRequest{
|
||||||
|
Email: "a@b.c",
|
||||||
|
Password: "weak",
|
||||||
|
})
|
||||||
|
if err == nil || err.Error() != `tries to login as "a@b.c", but sent an invalid password` {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AuthenticateUserWithPassword_UnverifiedEmail(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
|
||||||
|
authUser := &happydns.UserAuth{
|
||||||
|
Email: "a@b.c",
|
||||||
|
}
|
||||||
|
err := authUser.DefinePassword("v3rySecure")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mem.CreateAuthUser(authUser)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, nil, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{}, mem, userUsecase)
|
||||||
|
|
||||||
|
_, err = authenticationUsecase.AuthenticateUserWithPassword(happydns.LoginRequest{
|
||||||
|
Email: "a@b.c",
|
||||||
|
Password: "v3rySecure",
|
||||||
|
})
|
||||||
|
if err == nil || err.Error() != `tries to login as "a@b.c", but has not verified email` {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AuthenticateUserWithPassword_NoEmail(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
|
||||||
|
authUser := &happydns.UserAuth{
|
||||||
|
Email: "a@b.c",
|
||||||
|
}
|
||||||
|
err := authUser.DefinePassword("v3rySecure")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mem.CreateAuthUser(authUser)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, nil, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{NoMail: true}, mem, userUsecase)
|
||||||
|
|
||||||
|
_, err = authenticationUsecase.AuthenticateUserWithPassword(happydns.LoginRequest{
|
||||||
|
Email: "a@b.c",
|
||||||
|
Password: "v3rySecure",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AuthenticateUserWithPassword(t *testing.T) {
|
||||||
|
mem, _ := inmemory.NewInMemoryStorage()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
authUser := &happydns.UserAuth{
|
||||||
|
Email: "a@b.c",
|
||||||
|
EmailVerification: &now,
|
||||||
|
}
|
||||||
|
err := authUser.DefinePassword("v3rySecure")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mem.CreateAuthUser(authUser)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userUsecase := userUC.NewUserUsecases(mem, nil, nil, nil)
|
||||||
|
authenticationUsecase := usecase.NewAuthenticationUsecase(&happydns.Options{}, mem, userUsecase)
|
||||||
|
|
||||||
|
_, err = authenticationUsecase.AuthenticateUserWithPassword(happydns.LoginRequest{
|
||||||
|
Email: "a@b.c",
|
||||||
|
Password: "v3rySecure",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
122
internal/usecase/authuser/account_recovery_test.go
Normal file
122
internal/usecase/authuser/account_recovery_test.go
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/mail"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenAccountRecoveryHash(t *testing.T) {
|
||||||
|
recoveryKey := make([]byte, 64)
|
||||||
|
hash := authuser.GenAccountRecoveryHash(recoveryKey, false)
|
||||||
|
if hash == "" {
|
||||||
|
t.Error("Expected non-empty hash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanRecoverAccount(t *testing.T) {
|
||||||
|
recoveryKey := make([]byte, 64)
|
||||||
|
user := &happydns.UserAuth{PasswordRecoveryKey: recoveryKey}
|
||||||
|
hash := authuser.GenAccountRecoveryHash(recoveryKey, false)
|
||||||
|
|
||||||
|
err := authuser.CanRecoverAccount(user, hash)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type dummyMailer struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *dummyMailer) SendMail(to *mail.Address, subject, content string) (err error) {
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateLink(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewRecoverAccountUsecase(store, nil, config, nil)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com"}
|
||||||
|
|
||||||
|
link, err := uc.GenerateLink(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if link == "" {
|
||||||
|
t.Error("Expected non-empty link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendLink(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mailer := &dummyMailer{}
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewRecoverAccountUsecase(store, mailer, config, nil)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com"}
|
||||||
|
|
||||||
|
err := uc.SendLink(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendLink_Error(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mailer := &dummyMailer{err: errors.New("SMTP Error")}
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewRecoverAccountUsecase(store, mailer, config, nil)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com"}
|
||||||
|
|
||||||
|
err := uc.SendLink(user)
|
||||||
|
if err == nil || err.Error() != "SMTP Error" {
|
||||||
|
t.Errorf("Expected SMTP Error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResetPassword(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mailer := &dummyMailer{}
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
changePassword := authuser.NewChangePasswordUsecase(store, authuser.NewCheckPasswordConstraintsUsecase())
|
||||||
|
|
||||||
|
uc := authuser.NewRecoverAccountUsecase(store, mailer, config, changePassword)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com", PasswordRecoveryKey: make([]byte, 64)}
|
||||||
|
|
||||||
|
err := uc.ResetPassword(user, happydns.AccountRecoveryForm{
|
||||||
|
Key: authuser.GenAccountRecoveryHash(user.PasswordRecoveryKey, false),
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous recovery hash should work too
|
||||||
|
err = uc.ResetPassword(user, happydns.AccountRecoveryForm{
|
||||||
|
Key: authuser.GenAccountRecoveryHash(user.PasswordRecoveryKey, true),
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid key should not work
|
||||||
|
otherKey := make([]byte, 64)
|
||||||
|
otherKey[1] = byte('a')
|
||||||
|
err = uc.ResetPassword(user, happydns.AccountRecoveryForm{
|
||||||
|
Key: authuser.GenAccountRecoveryHash(otherKey, true),
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
})
|
||||||
|
if err == nil || !strings.HasPrefix(err.Error(), "The account recovery link you follow is invalid or has expired (it is valid during ") {
|
||||||
|
t.Errorf("Expected invalid recovery link, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
51
internal/usecase/authuser/can_register_test.go
Normal file
51
internal/usecase/authuser/can_register_test.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// This file is part of the happyDomain (R) project.
|
||||||
|
// Copyright (c) 2020-2025 happyDomain
|
||||||
|
// Authors: Pierre-Olivier Mercier, et al.
|
||||||
|
//
|
||||||
|
// This program is offered under a commercial and under the AGPL license.
|
||||||
|
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||||
|
//
|
||||||
|
// For AGPL licensing:
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCanRegisterUsecase_IsOpened(t *testing.T) {
|
||||||
|
// Test case where registration is enabled
|
||||||
|
t.Run("Registration is enabled", func(t *testing.T) {
|
||||||
|
cfg := &happydns.Options{DisableRegistration: false}
|
||||||
|
uc := authuser.NewCanRegisterUsecase(cfg)
|
||||||
|
|
||||||
|
if !uc.IsOpened() {
|
||||||
|
t.Errorf("Expected registration to be enabled")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test case where registration is disabled
|
||||||
|
t.Run("Registration is disabled", func(t *testing.T) {
|
||||||
|
cfg := &happydns.Options{DisableRegistration: true}
|
||||||
|
uc := authuser.NewCanRegisterUsecase(cfg)
|
||||||
|
|
||||||
|
if uc.IsOpened() {
|
||||||
|
t.Errorf("Expected registration to be disabled")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
125
internal/usecase/authuser/change_password_test.go
Normal file
125
internal/usecase/authuser/change_password_test.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// This file is part of the happyDomain (R) project.
|
||||||
|
// Copyright (c) 2020-2025 happyDomain
|
||||||
|
// Authors: Pierre-Olivier Mercier, et al.
|
||||||
|
//
|
||||||
|
// This program is offered under a commercial and under the AGPL license.
|
||||||
|
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||||
|
//
|
||||||
|
// For AGPL licensing:
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChangePasswordUsecase_Change(t *testing.T) {
|
||||||
|
// Setup in-memory storage
|
||||||
|
storage, _ := inmemory.NewInMemoryStorage()
|
||||||
|
user := &happydns.UserAuth{
|
||||||
|
Email: "test@example.com",
|
||||||
|
}
|
||||||
|
user.DefinePassword("oldpassword")
|
||||||
|
|
||||||
|
// Create a user in the storage
|
||||||
|
err := storage.CreateAuthUser(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the usecase
|
||||||
|
checkPasswordConstraints := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
uc := authuser.NewChangePasswordUsecase(storage, checkPasswordConstraints)
|
||||||
|
|
||||||
|
// Test changing password
|
||||||
|
newPassword := "newPa$$w0rd"
|
||||||
|
err = uc.Change(user, newPassword)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the password was changed
|
||||||
|
updatedUser, err := storage.GetAuthUser(user.Id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if !updatedUser.CheckPassword(newPassword) {
|
||||||
|
t.Error("Expected password to be updated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangePasswordUsecase_CheckNewPassword(t *testing.T) {
|
||||||
|
// Setup in-memory storage
|
||||||
|
storage, _ := inmemory.NewInMemoryStorage()
|
||||||
|
user := &happydns.UserAuth{
|
||||||
|
Email: "test@example.com",
|
||||||
|
}
|
||||||
|
user.DefinePassword("oldpassword")
|
||||||
|
|
||||||
|
// Create a user in the storage
|
||||||
|
err := storage.CreateAuthUser(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the usecase
|
||||||
|
checkPasswordConstraints := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
uc := authuser.NewChangePasswordUsecase(storage, checkPasswordConstraints)
|
||||||
|
|
||||||
|
// Test checking new password with correct current password
|
||||||
|
form := happydns.ChangePasswordForm{
|
||||||
|
Current: "oldpassword",
|
||||||
|
Password: "newPa$$w0rd",
|
||||||
|
PasswordConfirm: "newPa$$w0rd",
|
||||||
|
}
|
||||||
|
err = uc.CheckNewPassword(user, form)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test checking new password with incorrect current password
|
||||||
|
form.Current = "wrongpassword"
|
||||||
|
err = uc.CheckNewPassword(user, form)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for incorrect current password")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangePasswordUsecase_CheckResetPassword(t *testing.T) {
|
||||||
|
// Setup the usecase
|
||||||
|
checkPasswordConstraints := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
uc := authuser.NewChangePasswordUsecase(nil, checkPasswordConstraints)
|
||||||
|
|
||||||
|
// Test checking reset password with matching passwords
|
||||||
|
form := happydns.ChangePasswordForm{
|
||||||
|
Password: "newPa$$w0rd",
|
||||||
|
PasswordConfirm: "newPa$$w0rd",
|
||||||
|
}
|
||||||
|
err := uc.CheckResetPassword(&happydns.UserAuth{}, form)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test checking reset password with non-matching passwords
|
||||||
|
form.PasswordConfirm = "differentpassword"
|
||||||
|
err = uc.CheckResetPassword(&happydns.UserAuth{}, form)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for non-matching passwords")
|
||||||
|
}
|
||||||
|
}
|
144
internal/usecase/authuser/create_auth_user_test.go
Normal file
144
internal/usecase/authuser/create_auth_user_test.go
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/mailer"
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dummyEmailValidation struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyEmailValidation) GenerateLink(u *happydns.UserAuth) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyEmailValidation) SendLink(u *happydns.UserAuth) error {
|
||||||
|
return d.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyEmailValidation) Validate(user *happydns.UserAuth, form happydns.AddressValidationForm) error {
|
||||||
|
return d.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateAuthUser_Success(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
pwChecker := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
emailValidation := &dummyEmailValidation{}
|
||||||
|
usecase := authuser.NewCreateAuthUserUsecase(store, &mailer.Mailer{}, pwChecker, emailValidation)
|
||||||
|
|
||||||
|
reg := happydns.UserRegistration{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
Newsletter: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := usecase.Create(reg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Email != reg.Email {
|
||||||
|
t.Errorf("expected email %s, got %s", reg.Email, user.Email)
|
||||||
|
}
|
||||||
|
if user.Password == nil {
|
||||||
|
t.Errorf("expected defined password, got %s", user.Password)
|
||||||
|
}
|
||||||
|
if !user.AllowCommercials {
|
||||||
|
t.Error("expected user to have AllowCommercials = true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateAuthUser_InvalidEmail(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
pwChecker := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
usecase := authuser.NewCreateAuthUserUsecase(store, &mailer.Mailer{}, pwChecker, &dummyEmailValidation{})
|
||||||
|
|
||||||
|
reg := happydns.UserRegistration{
|
||||||
|
Email: "bademail",
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "the given email is invalid" {
|
||||||
|
t.Errorf("expected validation error for email, got: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateAuthUser_WeakPassword(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
pwChecker := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
usecase := authuser.NewCreateAuthUserUsecase(store, &mailer.Mailer{}, pwChecker, &dummyEmailValidation{})
|
||||||
|
|
||||||
|
reg := happydns.UserRegistration{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "123",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "password must be at least 8 characters long" {
|
||||||
|
t.Errorf("expected password constraint error, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.Password = "Secur3$"
|
||||||
|
_, err = usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "password must be at least 8 characters long" {
|
||||||
|
t.Errorf("expected password constraint error, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.Password = "secure123"
|
||||||
|
_, err = usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "Password must contain upper case letters." {
|
||||||
|
t.Errorf("expected password constraint error, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.Password = "Secure123"
|
||||||
|
_, err = usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "Password must be longer or contain symbols." {
|
||||||
|
t.Errorf("expected password constraint error, got: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateAuthUser_EmailAlreadyUsed(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
pwChecker := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
usecase := authuser.NewCreateAuthUserUsecase(store, &mailer.Mailer{}, pwChecker, &dummyEmailValidation{})
|
||||||
|
|
||||||
|
// Create a user first
|
||||||
|
reg := happydns.UserRegistration{
|
||||||
|
Email: "used@example.com",
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
}
|
||||||
|
_, err := usecase.Create(reg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("setup user creation failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try creating again with the same email
|
||||||
|
_, err = usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "an account already exists with the given address. Try logging in." {
|
||||||
|
t.Errorf("expected duplicate email error, got: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateAuthUser_EmailValidationFails(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
pwChecker := authuser.NewCheckPasswordConstraintsUsecase()
|
||||||
|
emailValidation := &dummyEmailValidation{err: errors.New("SMTP error")}
|
||||||
|
usecase := authuser.NewCreateAuthUserUsecase(store, &mailer.Mailer{}, pwChecker, emailValidation)
|
||||||
|
|
||||||
|
reg := happydns.UserRegistration{
|
||||||
|
Email: "fail@example.com",
|
||||||
|
Password: "StrongPassword123!",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := usecase.Create(reg)
|
||||||
|
if err == nil || err.Error() != "unable to send validation email: SMTP error" {
|
||||||
|
t.Errorf("expected internal error for email sending, got: %v", err)
|
||||||
|
}
|
||||||
|
}
|
101
internal/usecase/authuser/delete_auth_user_test.go
Normal file
101
internal/usecase/authuser/delete_auth_user_test.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// This file is part of the happyDomain (R) project.
|
||||||
|
// Copyright (c) 2020-2025 happyDomain
|
||||||
|
// Authors: Pierre-Olivier Mercier, et al.
|
||||||
|
//
|
||||||
|
// This program is offered under a commercial and under the AGPL license.
|
||||||
|
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||||
|
//
|
||||||
|
// For AGPL licensing:
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockCloseUserSessionsUsecase is a mock implementation of CloseUserSessionsUsecase.
|
||||||
|
type MockCloseUserSessionsUsecase struct {
|
||||||
|
CloseAllFunc func(user happydns.UserInfo) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockCloseUserSessionsUsecase) CloseAll(user happydns.UserInfo) error {
|
||||||
|
return m.CloseAllFunc(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockCloseUserSessionsUsecase) ByID(userID happydns.Identifier) error {
|
||||||
|
return m.CloseAll(&happydns.UserAuth{Id: userID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteAuthUserUsecase_Delete(t *testing.T) {
|
||||||
|
// Create an in-memory storage
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
|
||||||
|
// Create a mock for CloseUserSessionsUsecase
|
||||||
|
mockCloseUserSessions := &MockCloseUserSessionsUsecase{
|
||||||
|
CloseAllFunc: func(user happydns.UserInfo) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an instance of DeleteAuthUserUsecase
|
||||||
|
uc := authuser.NewDeleteAuthUserUsecase(store, mockCloseUserSessions)
|
||||||
|
|
||||||
|
// Create a test user
|
||||||
|
user := &happydns.UserAuth{
|
||||||
|
Email: "test@example.com",
|
||||||
|
}
|
||||||
|
user.DefinePassword("test-password")
|
||||||
|
|
||||||
|
// Add the user to the storage
|
||||||
|
err := store.CreateAuthUser(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case 1: Invalid password
|
||||||
|
err = uc.Delete(user, "wrong-password")
|
||||||
|
if err == nil || err.Error() != "invalid current password" {
|
||||||
|
t.Errorf("Expected error 'invalid current password', got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case 2: Error in closing sessions
|
||||||
|
mockCloseUserSessions.CloseAllFunc = func(user happydns.UserInfo) error {
|
||||||
|
return fmt.Errorf("error closing sessions")
|
||||||
|
}
|
||||||
|
err = uc.Delete(user, "test-password")
|
||||||
|
if err == nil || err.Error() != "unable to delete user sessions: error closing sessions" {
|
||||||
|
t.Errorf("Expected error 'unable to delete user sessions: error closing sessions', got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case 3: Bad password when deleting user
|
||||||
|
err = uc.Delete(user, "bad-password")
|
||||||
|
if err == nil || err.Error() != "invalid current password" {
|
||||||
|
t.Errorf("Expected error 'invalid current password', got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case 4: Successful deletion
|
||||||
|
mockCloseUserSessions.CloseAllFunc = func(user happydns.UserInfo) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = uc.Delete(user, "test-password")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
95
internal/usecase/authuser/email_validation_test.go
Normal file
95
internal/usecase/authuser/email_validation_test.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenEmailValidationHash(t *testing.T) {
|
||||||
|
hash := authuser.GenRegistrationHash(&happydns.UserAuth{CreatedAt: time.Now()}, false)
|
||||||
|
if hash == "" {
|
||||||
|
t.Error("Expected non-empty hash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateRegistrationLink(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewEmailValidationUsecase(store, nil, config)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com"}
|
||||||
|
|
||||||
|
link := uc.GenerateLink(user)
|
||||||
|
if link == "" {
|
||||||
|
t.Error("Expected non-empty link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendRegistrationLink(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mailer := &dummyMailer{}
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewEmailValidationUsecase(store, mailer, config)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com"}
|
||||||
|
|
||||||
|
err := uc.SendLink(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendRegistrationLink_Error(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mailer := &dummyMailer{err: errors.New("SMTP Error")}
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewEmailValidationUsecase(store, mailer, config)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com"}
|
||||||
|
|
||||||
|
err := uc.SendLink(user)
|
||||||
|
if err == nil || err.Error() != "SMTP Error" {
|
||||||
|
t.Errorf("Expected SMTP Error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateEmail(t *testing.T) {
|
||||||
|
store, _ := inmemory.NewInMemoryStorage()
|
||||||
|
mailer := &dummyMailer{}
|
||||||
|
config := &happydns.Options{ExternalURL: url.URL{Scheme: "http", Host: "example.com"}}
|
||||||
|
|
||||||
|
uc := authuser.NewEmailValidationUsecase(store, mailer, config)
|
||||||
|
user := &happydns.UserAuth{Id: []byte("user1"), Email: "user@example.com", PasswordRecoveryKey: make([]byte, 64)}
|
||||||
|
|
||||||
|
err := uc.Validate(user, happydns.AddressValidationForm{
|
||||||
|
Key: authuser.GenRegistrationHash(user, false),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous recovery hash should work too
|
||||||
|
err = uc.Validate(user, happydns.AddressValidationForm{
|
||||||
|
Key: authuser.GenRegistrationHash(user, true),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-matching user creation time should not work
|
||||||
|
user2 := *user
|
||||||
|
user2.CreatedAt = time.Now()
|
||||||
|
err = uc.Validate(user, happydns.AddressValidationForm{
|
||||||
|
Key: authuser.GenRegistrationHash(&user2, false),
|
||||||
|
})
|
||||||
|
if err == nil || !strings.HasPrefix(err.Error(), "bad email validation key: the validation address link you follow is invalid or has expired (it is valid during ") {
|
||||||
|
t.Errorf("Expected invalid validation link, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
71
internal/usecase/authuser/get_auth_user_test.go
Normal file
71
internal/usecase/authuser/get_auth_user_test.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package authuser_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.happydns.org/happyDomain/internal/storage/inmemory"
|
||||||
|
"git.happydns.org/happyDomain/internal/usecase/authuser"
|
||||||
|
"git.happydns.org/happyDomain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetAuthUserUsecase(t *testing.T) {
|
||||||
|
memStore, err := inmemory.NewInMemoryStorage()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create in-memory storage: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
user := &happydns.UserAuth{
|
||||||
|
Email: "test@example.com",
|
||||||
|
EmailVerification: &now,
|
||||||
|
CreatedAt: now,
|
||||||
|
LastLoggedIn: &now,
|
||||||
|
Password: []byte("fakehash"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new user in memory (and assign an ID)
|
||||||
|
err = memStore.CreateAuthUser(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create auth user: %v", err)
|
||||||
|
}
|
||||||
|
if user.Id == nil {
|
||||||
|
t.Fatalf("Expected non-nil user ID, got %s", user.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
uc := authuser.NewGetAuthUserUsecase(memStore)
|
||||||
|
|
||||||
|
t.Run("ByID returns the correct user", func(t *testing.T) {
|
||||||
|
got, err := uc.ByID(user.Id)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if got.Email != "test@example.com" {
|
||||||
|
t.Errorf("Expected email 'test@example.com', got %s", got.Email)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ByEmail returns the correct user", func(t *testing.T) {
|
||||||
|
got, err := uc.ByEmail("test@example.com")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if !got.Id.Equals(user.Id) {
|
||||||
|
t.Errorf("Expected ID '%s', got %s", user.Id, got.Id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ByID returns error for unknown ID", func(t *testing.T) {
|
||||||
|
_, err := uc.ByID([]byte("unknown-id"))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for unknown ID, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ByEmail returns error for unknown email", func(t *testing.T) {
|
||||||
|
_, err := uc.ByEmail("unknown@example.com")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for unknown email, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue