From 0fab1e1f2eb2421d3c46b064f9e9e3704e99b744 Mon Sep 17 00:00:00 2001 From: Tim Wundenberg Date: Sun, 6 Oct 2024 10:05:00 +0200 Subject: [PATCH] fix: missing service tests #181 --- .mockery.yaml | 1 + handler/auth.go | 2 +- handler/default.go | 3 +- service/auth.go | 20 +++++------ service/auth_test.go | 80 ++++++++++++++++++++++++++++++++++++++++---- service/mail.go | 12 ++++--- 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/.mockery.yaml b/.mockery.yaml index 50c6e2e..b5f727d 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -6,6 +6,7 @@ packages: interfaces: RandomGenerator: Clock: + MailService: me-fit/db: interfaces: DbAuth: diff --git a/handler/auth.go b/handler/auth.go index 6c7529a..ea155fb 100644 --- a/handler/auth.go +++ b/handler/auth.go @@ -145,7 +145,7 @@ func (handler HandlerAuthImpl) handleSignUp() http.HandlerFunc { return nil, err } - go handler.service.SendVerificationMail(user) + go handler.service.SendVerificationMail(user.Id, user.Email) return nil, nil }) diff --git a/handler/default.go b/handler/default.go index 6244f08..ea0cf5a 100644 --- a/handler/default.go +++ b/handler/default.go @@ -18,7 +18,8 @@ func GetHandler(d *sql.DB, serverSettings *types.ServerSettings) http.Handler { randomGenerator := service.NewRandomGeneratorImpl() clock := service.NewClockImpl() dbAuth := db.NewDbAuthSqlite(d) - serviceAuth := service.NewServiceAuthImpl(dbAuth, randomGenerator, clock, serverSettings) + mailService := service.NewMailServiceImpl(serverSettings) + serviceAuth := service.NewServiceAuthImpl(dbAuth, randomGenerator, clock, mailService, serverSettings) handlerAuth := NewHandlerAuth(d, serviceAuth, serverSettings) // Serve static files (CSS, JS and images) diff --git a/service/auth.go b/service/auth.go index 7998b64..c1f3663 100644 --- a/service/auth.go +++ b/service/auth.go @@ -47,24 +47,24 @@ func NewUser(user *db.User) *User { type ServiceAuth interface { SignIn(email string, password string) (*User, error) SignUp(email string, password string) (*User, error) - SendVerificationMail(user *User) + SendVerificationMail(userId uuid.UUID, email string) } type ServiceAuthImpl struct { dbAuth db.DbAuth randomGenerator RandomGenerator clock Clock - serverSettings *types.ServerSettings mailService MailService + serverSettings *types.ServerSettings } -func NewServiceAuthImpl(dbAuth db.DbAuth, randomGenerator RandomGenerator, clock Clock, serverSettings *types.ServerSettings) *ServiceAuthImpl { +func NewServiceAuthImpl(dbAuth db.DbAuth, randomGenerator RandomGenerator, clock Clock, mailService MailService, serverSettings *types.ServerSettings) *ServiceAuthImpl { return &ServiceAuthImpl{ dbAuth: dbAuth, randomGenerator: randomGenerator, clock: clock, + mailService: mailService, serverSettings: serverSettings, - mailService: NewMailService(serverSettings), } } @@ -123,10 +123,10 @@ func (service ServiceAuthImpl) SignUp(email string, password string) (*User, err return NewUser(dbUser), nil } -func (service ServiceAuthImpl) SendVerificationMail(user *User) { +func (service ServiceAuthImpl) SendVerificationMail(userId uuid.UUID, email string) { var token string - token, err := service.dbAuth.GetEmailVerificationToken(user.Id) + token, err := service.dbAuth.GetEmailVerificationToken(userId) if err != nil { return } @@ -137,7 +137,7 @@ func (service ServiceAuthImpl) SendVerificationMail(user *User) { return } - err = service.dbAuth.InsertEmailVerificationToken(user.Id, token) + err = service.dbAuth.InsertEmailVerificationToken(userId, token) if err != nil { return } @@ -150,7 +150,7 @@ func (service ServiceAuthImpl) SendVerificationMail(user *User) { return } - service.mailService.SendMail(user.Email, "Welcome to ME-FIT", w.String()) + service.mailService.SendMail(email, "Welcome to ME-FIT", w.String()) } // TODO @@ -311,7 +311,7 @@ func HandleSignOutComp(db *sql.DB) http.HandlerFunc { } func HandleDeleteAccountComp(db *sql.DB, serverSettings *types.ServerSettings) http.HandlerFunc { - mailService := NewMailService(serverSettings) + mailService := NewMailServiceImpl(serverSettings) return func(w http.ResponseWriter, r *http.Request) { user := utils.GetUserFromSession(db, r) if user == nil { @@ -508,7 +508,7 @@ func HandleActualResetPasswordComp(db *sql.DB) http.HandlerFunc { } func HandleResetPasswordComp(db *sql.DB, serverSettings *types.ServerSettings) http.HandlerFunc { - mailService := NewMailService(serverSettings) + mailService := NewMailServiceImpl(serverSettings) return func(w http.ResponseWriter, r *http.Request) { email := r.FormValue("email") diff --git a/service/auth_test.go b/service/auth_test.go index 78cb7ef..aeede82 100644 --- a/service/auth_test.go +++ b/service/auth_test.go @@ -4,6 +4,7 @@ import ( "me-fit/db" "me-fit/mocks" "me-fit/types" + "strings" "errors" "testing" @@ -11,6 +12,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestSignIn(t *testing.T) { @@ -35,8 +37,9 @@ func TestSignIn(t *testing.T) { mockDbAuth.EXPECT().GetUser("test@test.de").Return(user, nil) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) actualUser, err := underTest.SignIn(user.Email, "password") assert.Nil(t, err) @@ -70,8 +73,9 @@ func TestSignIn(t *testing.T) { mockDbAuth.EXPECT().GetUser(user.Email).Return(user, nil) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) _, err := underTest.SignIn("test@test.de", "wrong password") @@ -84,8 +88,9 @@ func TestSignIn(t *testing.T) { mockDbAuth.EXPECT().GetUser("test").Return(nil, db.ErrUserNotFound) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) _, err := underTest.SignIn("test", "test") assert.Equal(t, ErrInvaidCredentials, err) @@ -97,8 +102,9 @@ func TestSignIn(t *testing.T) { mockDbAuth.EXPECT().GetUser("test").Return(nil, errors.New("Some undefined error")) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) _, err := underTest.SignIn("test", "test") @@ -114,8 +120,9 @@ func TestSignUp(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) _, err := underTest.SignUp("invalid email address", "SomeStrongPassword123!") @@ -127,8 +134,9 @@ func TestSignUp(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) weakPasswords := []string{ "123!ab", // too short @@ -148,6 +156,7 @@ func TestSignUp(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockRandom := mocks.NewMockRandomGenerator(t) mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) expected := User{ Id: uuid.New(), @@ -169,7 +178,7 @@ func TestSignUp(t *testing.T) { mockDbAuth.EXPECT().InsertUser(db.NewUser(expected.Id, expected.Email, false, nil, false, GetHashPassword(password, salt), salt, createTime)).Return(nil) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) actual, err := underTest.SignUp(expected.Email, password) @@ -177,4 +186,61 @@ func TestSignUp(t *testing.T) { assert.Equal(t, expected, *actual) }) + t.Run("should return ErrAccountExists", func(t *testing.T) { + t.Parallel() + + mockDbAuth := mocks.NewMockDbAuth(t) + mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) + + user := User{ + Id: uuid.New(), + Email: "some@valid.email", + } + + random := NewRandomGeneratorImpl() + salt, err := random.Bytes(16) + assert.Nil(t, err) + password := "SomeStrongPassword123!" + + mockRandom.EXPECT().UUID().Return(user.Id, nil) + mockRandom.EXPECT().Bytes(16).Return(salt, nil) + + createTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + + mockClock.EXPECT().Now().Return(createTime) + + mockDbAuth.EXPECT().InsertUser(db.NewUser(user.Id, user.Email, false, nil, false, GetHashPassword(password, salt), salt, createTime)).Return(db.ErrUserExists) + + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) + + _, err = underTest.SignUp(user.Email, password) + assert.Equal(t, ErrAccountExists, err) + }) +} + +func TestSendVerificationMail(t *testing.T) { + + t.Parallel() + t.Run("should use stored token and send mail", func(t *testing.T) { + t.Parallel() + + token := "someRandomTokenToUse" + email := "some@email.de" + userId := uuid.New() + + mockDbAuth := mocks.NewMockDbAuth(t) + mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) + mockMail := mocks.NewMockMailService(t) + + mockDbAuth.EXPECT().GetEmailVerificationToken(userId).Return(token, nil) + + mockMail.EXPECT().SendMail(email, "Welcome to ME-FIT", mock.MatchedBy(func(message string) bool { return strings.Contains(message, token) })).Return(nil) + + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, mockMail, &types.ServerSettings{}) + + underTest.SendVerificationMail(userId, email) + }) } diff --git a/service/mail.go b/service/mail.go index f60d0b4..0505edb 100644 --- a/service/mail.go +++ b/service/mail.go @@ -6,15 +6,19 @@ import ( "net/smtp" ) -type MailService struct { +type MailService interface { + SendMail(to string, subject string, message string) error +} + +type MailServiceImpl struct { serverSettings *types.ServerSettings } -func NewMailService(serverSettings *types.ServerSettings) MailService { - return MailService{serverSettings: serverSettings} +func NewMailServiceImpl(serverSettings *types.ServerSettings) MailServiceImpl { + return MailServiceImpl{serverSettings: serverSettings} } -func (m MailService) SendMail(to string, subject string, message string) error { +func (m MailServiceImpl) SendMail(to string, subject string, message string) error { if m.serverSettings.Smtp == nil { return nil }